Hello community, here is the log from the commit of package tigervnc.14864 for openSUSE:Leap:15.1:Update checked in at 2020-11-05 20:25:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.1:Update/tigervnc.14864 (Old) and /work/SRC/openSUSE:Leap:15.1:Update/.tigervnc.14864.new.11331 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "tigervnc.14864" Thu Nov 5 20:25:46 2020 rev:1 rq:845504 version:1.9.0 Changes: -------- New Changes file: --- /dev/null 2020-10-22 01:51:33.322291705 +0200 +++ /work/SRC/openSUSE:Leap:15.1:Update/.tigervnc.14864.new.11331/tigervnc.changes 2020-11-05 20:25:48.171280402 +0100 @@ -0,0 +1,716 @@ +------------------------------------------------------------------- +Fri Sep 25 14:29:00 UTC 2020 - Stefan Dirsch <sndir...@suse.com> + +- CVE-2020-26117: Server certificates were stored as certiticate + authoritied, allowing malicious owners of these certificates + to impersonate any server after a client had added an exception + (boo#1176733) + * U_0001-Properly-store-certificate-exceptions.patch, + U_0002-Properly-store-certificate-exceptions-in-Java-viewer.patch + * Properly store certificate exceptions (boo#1176733) +- adjusted u_tigervnc-add-autoaccept-parameter.patch + +------------------------------------------------------------------- +Wed May 13 13:02:11 UTC 2020 - Stefan Dirsch <sndir...@suse.com> + +- U_Avoid-potential-crash-when-replacing-buffer-in-Plain.patch + * fixes crash in free() when using "-f" option of vncpasswd + command (bsc#1171519) + +------------------------------------------------------------------- +Wed Jan 8 11:32:07 UTC 2020 - Stefan Dirsch <sndir...@suse.com> + +- TigerVNC security fix: + 0001-Make-ZlibInStream-more-robust-against-failures.patch + 0002-Encapsulate-PixelBuffer-internal-details.patch + 0003-Restrict-PixelBuffer-dimensions-to-safe-values.patch + 0004-Add-write-protection-to-OffsetPixelBuffer.patch + 0005-Handle-empty-Tight-gradient-rects.patch + 0006-Add-unit-test-for-PixelFormat-sanity-checks.patch + 0007-Fix-depth-sanity-test-in-PixelFormat.patch + 0008-Add-sanity-checks-for-PixelFormat-shift-values.patch + 0009-Remove-unused-FixedMemOutStream.patch + 0010-Use-size_t-for-lengths-in-stream-objects.patch + 0011-Be-defensive-about-overflows-in-stream-objects.patch + 0012-Add-unit-tests-for-PixelFormat.is888-detection.patch + 0013-Handle-pixel-formats-with-odd-shift-values.patch + * stack use-after-return due to incorrect usage of stack memory + in ZRLEDecoder (CVE-2019-15691, bsc#1159856) + * improper value checks in CopyRectDecode may lead to heap + buffer overflow (CVE-2019-15692, bsc#1160250) + * heap buffer overflow in TightDecoder::FilterGradient + (CVE-2019-15693, bsc#1159858) + * improper error handling in processing MemOutStream may lead + to heap buffer overflow (CVE-2019-15694, bsc#1160251 + * stack buffer overflow, which could be triggered from + CMsgReader::readSetCurso (CVE-2019-15695, bsc#1159860) + +------------------------------------------------------------------- +Thu Jan 17 12:07:27 UTC 2019 - m...@suse.com + +- Switch websocket dependency to python3. (bsc#1119737) + +------------------------------------------------------------------- +Thu Jan 17 10:21:29 UTC 2019 - m...@suse.com + +- Do not build xorg-x11-Xvnc-module on s390. It fails to build + because macros.xorg-server is incomplete on s390 and the module + would be useless without real X server anyway. + +------------------------------------------------------------------- +Tue Jan 8 12:38:42 UTC 2019 - m...@suse.com + +- Add U_viewer-reset-ctrl-alt-to-menu-state-on-focus.patch + * Fix the ALT and CTRL buttons in viewer's F8 menu. (bsc#1119354) + +------------------------------------------------------------------- +Wed Sep 19 21:19:21 UTC 2018 - Jason Sikes <jsi...@suse.de> + +- Changed "openssl" requirement to "openssl(cli)" + * (bsc#1101470) + +------------------------------------------------------------------- +Mon Aug 6 12:04:52 UTC 2018 - m...@suse.com + +- Add xvnc.target to fix xvnc-novnc.service's dependency. + (bnc#1103552) +- Split the X server's VNC module into subpackage and give it + dependency on the current extension ABI. + +------------------------------------------------------------------- +Thu Aug 2 08:31:09 UTC 2018 - m...@suse.com + +- Update to tigervnc 1.9.0 + * Alternative, "raw" keyboard mode in the native client and all servers + * CapsLock/NumLock/ScrollLock synchronisation in the native client and all servers + * Automatic "repair" of JPEG artefacts on screen in all servers + * Support for UNIX sockets in the native client and in the UNIX servers + * Both clients now warn when sending the password over a possibly insecure channel + * Performance improvements in the Java client + * The Java client now requires Java 7 + * Improved high latency handling in all servers + * Slightly better keyboard handling in x0vncserver + * x0vncserver now supports cursors and screen resize + * Xorg 1.20 can now be used as a base for Xvnc/libvnc.so + - Fixes bnc#1103537 + +- Removed patches (included in 1.9.0): + * u_tigervnc-show-unencrypted-warning.patch + * U_allow_multiple_certs_with_same_dn_in_saved_certs_file.patch + * U_handle_certificate_verification_for_saved_certs_correctly.patch + * u_Unset-pixel-buffer-when-x0vncserver-client-disconnect.patch + * u_add-support-for-X-server-1.20.0.patch + * U_vncviewer-Fix-fullscreen-scrolling.patch + * U_vncviewer-Fix-scrollbar-visibility.patch + +- Removed patches (no longer needed): + * tigervnc-1.8.0-nowindows.patch + +- Refreshed patches: + * n_tigervnc-date-time.patch + * tigervnc-clean-pressed-key-on-exit.patch + * u_tigervnc-add-autoaccept-parameter.patch + * u_tigervnc-ignore-epipe-on-write.patch + +- Added patches: + * n_correct_path_in_desktop_file.patch + +- Fixed typo in 10-libvnc.conf + +------------------------------------------------------------------- +Fri Jun 8 09:09:38 UTC 2018 - m...@suse.com + +- Updated u_add-support-for-X-server-1.20.0.patch to version sent + upstream. Fixes GLX initialization. + +------------------------------------------------------------------- +Wed Jun 6 09:07:23 UTC 2018 - m...@suse.com + +- U_vncviewer-Fix-fullscreen-scrolling.patch, + U_vncviewer-Fix-scrollbar-visibility.patch + * Fix scrolling in vncviewer. (boo#1095664) + +- u_add-support-for-X-server-1.20.0.patch + * Fix build against X server 1.20.0. + +------------------------------------------------------------------- +Tue Apr 24 09:16:59 UTC 2018 - m...@suse.com + +- Reload firewalld files after installation. + +------------------------------------------------------------------- +Wed Apr 11 09:48:51 UTC 2018 - jeng...@inai.de + +- Limit feature description to openSUSE. Ensure neutrality of + description. + +------------------------------------------------------------------- +Wed Apr 11 08:12:52 UTC 2018 - m...@suse.com + +- Add u_change-button-layout-in-ServerDialog.patch + * To fit strings in languages with longer words... (bnc#1084865) +- Refresh n_tigervnc-date-time.patch + * Completely hide the build time (bnc#1082968) + +------------------------------------------------------------------- +Thu Mar 22 14:27:28 UTC 2018 - m...@suse.com + +- Enable xvnc.socket if upgraded from previous installation that + had VNC enabled in xinetd configuration. (bnc#1085974) +- Subpackage xorg-x11-Xvnc must also obsolete tightvnc. + +------------------------------------------------------------------- +Wed Feb 28 12:19:52 UTC 2018 - m...@suse.com + +- Replace SuSEFirewall2 by firewalld. (bnc#1081952) + +------------------------------------------------------------------- +Mon Dec 18 16:44:20 UTC 2017 - dims...@opensuse.org + +- Do not mess with /usr/lib*64)?/debug: this is RPM's playground + for debuginfo packages. + +------------------------------------------------------------------- +Mon Dec 18 14:56:17 UTC 2017 - fst...@suse.com + +- Added patch: + * tigervnc-1.8.0-nowindows.patch + + Remove Windows code that is removed from jdk10 + +------------------------------------------------------------------- +Tue Dec 12 13:15:25 UTC 2017 - m...@suse.com + +- Depend on pkgconfig's gl, egl and gbm instead of Mesa-devel. + * Those dependencies are what the underlying X server really + needs. Mesa-devel is too general and is a bottleneck in + distribution build. (bnc#1071297) + +------------------------------------------------------------------- +Tue Sep 26 11:53:23 UTC 2017 - m...@suse.com + +- u_Unset-pixel-buffer-when-x0vncserver-client-disconnect.patch + * Fixes crash in x0vncserver after client disconnects. + (bnc#1058587) + +------------------------------------------------------------------- +Mon Sep 25 08:36:07 UTC 2017 - m...@suse.com + ++++ 519 more lines (skipped) ++++ between /dev/null ++++ and /work/SRC/openSUSE:Leap:15.1:Update/.tigervnc.14864.new.11331/tigervnc.changes New: ---- 0001-Make-ZlibInStream-more-robust-against-failures.patch 0002-Encapsulate-PixelBuffer-internal-details.patch 0003-Restrict-PixelBuffer-dimensions-to-safe-values.patch 0004-Add-write-protection-to-OffsetPixelBuffer.patch 0005-Handle-empty-Tight-gradient-rects.patch 0006-Add-unit-test-for-PixelFormat-sanity-checks.patch 0007-Fix-depth-sanity-test-in-PixelFormat.patch 0008-Add-sanity-checks-for-PixelFormat-shift-values.patch 0009-Remove-unused-FixedMemOutStream.patch 0010-Use-size_t-for-lengths-in-stream-objects.patch 0011-Be-defensive-about-overflows-in-stream-objects.patch 0012-Add-unit-tests-for-PixelFormat.is888-detection.patch 0013-Handle-pixel-formats-with-odd-shift-values.patch 10-libvnc.conf U_0001-Properly-store-certificate-exceptions.patch U_0002-Properly-store-certificate-exceptions-in-Java-viewer.patch U_Avoid-potential-crash-when-replacing-buffer-in-Plain.patch U_viewer-reset-ctrl-alt-to-menu-state-on-focus.patch index.vnc n_correct_path_in_desktop_file.patch n_tigervnc-date-time.patch tigervnc-clean-pressed-key-on-exit.patch tigervnc-https.firewalld tigervnc-newfbsize.patch tigervnc.changes tigervnc.firewalld tigervnc.spec u_build_libXvnc_as_separate_library.patch u_change-button-layout-in-ServerDialog.patch u_tigervnc-add-autoaccept-parameter.patch u_tigervnc-cve-2014-8240.patch u_tigervnc-ignore-epipe-on-write.patch u_tigervnc_update_default_vncxstartup.patch v1.9.0.tar.gz vnc-httpd.susefirewall vnc-server.susefirewall vnc.pam vnc.reg vncpasswd.arg with-vnc-key.sh x11vnc xvnc-novnc.service xvnc-novnc.socket xvnc.socket xvnc.target xvnc@.service ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ tigervnc.spec ++++++ # # spec file for package tigervnc # # Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via https://bugs.opensuse.org/ # %define vncgroup vnc %define vncuser vnc %define tlskey %{_sysconfdir}/vnc/tls.key %define tlscert %{_sysconfdir}/vnc/tls.cert %define _unitdir %{_prefix}/lib/systemd/system %if 0%{?suse_version} >= 1500 %define use_firewalld 1 %else %define use_firewalld 0 %endif Name: tigervnc Version: 1.9.0 Release: 0 Provides: tightvnc = 1.3.9 Obsoletes: tightvnc < 1.3.9 Provides: vnc BuildRequires: autoconf BuildRequires: automake BuildRequires: cmake BuildRequires: fltk-devel >= 1.3.3 BuildRequires: gcc-c++ BuildRequires: gcc-c++ BuildRequires: java-devel >= 1.6.0 BuildRequires: jpackage-utils BuildRequires: libjpeg-devel BuildRequires: libopenssl-devel BuildRequires: libtool BuildRequires: nasm BuildRequires: xorg-x11-server-sdk BuildRequires: xorg-x11-server-source BuildRequires: pkgconfig(x11) BuildRequires: pkgconfig(xext) BuildRequires: pkgconfig(xproto) BuildRequires: pkgconfig(xtst) # Because of keytool to build java client BuildRequires: libgcrypt-devel BuildRequires: libgpg-error-devel BuildRequires: mozilla-nss BuildRequires: pam-devel BuildRequires: pkg-config BuildRequires: systemd-rpm-macros BuildRequires: xmlto BuildRequires: xorg-x11-libICE-devel BuildRequires: xorg-x11-libSM-devel BuildRequires: pkgconfig(bigreqsproto) >= 1.1.0 BuildRequires: pkgconfig(compositeproto) >= 0.4 BuildRequires: pkgconfig(damageproto) >= 1.1 BuildRequires: pkgconfig(dri) BuildRequires: pkgconfig(egl) BuildRequires: pkgconfig(fixesproto) >= 4.1 BuildRequires: pkgconfig(fontsproto) BuildRequires: pkgconfig(fontutil) BuildRequires: pkgconfig(gbm) BuildRequires: pkgconfig(gl) BuildRequires: pkgconfig(glproto) BuildRequires: pkgconfig(gnutls) BuildRequires: pkgconfig(inputproto) >= 1.9.99.902 BuildRequires: pkgconfig(kbproto) >= 1.0.3 BuildRequires: pkgconfig(libtasn1) BuildRequires: pkgconfig(openssl) BuildRequires: pkgconfig(pciaccess) >= 0.8.0 BuildRequires: pkgconfig(pixman-1) >= 0.15.20 BuildRequires: pkgconfig(presentproto) >= 1.0 BuildRequires: pkgconfig(randrproto) >= 1.2.99.3 BuildRequires: pkgconfig(recordproto) >= 1.13.99.1 BuildRequires: pkgconfig(renderproto) >= 0.11 BuildRequires: pkgconfig(resourceproto) BuildRequires: pkgconfig(scrnsaverproto) >= 1.1 BuildRequires: pkgconfig(videoproto) BuildRequires: pkgconfig(xau) BuildRequires: pkgconfig(xcmiscproto) >= 1.2.0 BuildRequires: pkgconfig(xdmcp) BuildRequires: pkgconfig(xextproto) >= 7.0.99.3 BuildRequires: pkgconfig(xf86driproto) >= 2.1.1 BuildRequires: pkgconfig(xfont) >= 1.4.2 BuildRequires: pkgconfig(xfont2) BuildRequires: pkgconfig(xineramaproto) BuildRequires: pkgconfig(xkbfile) BuildRequires: pkgconfig(xorg-macros) >= 1.14 BuildRequires: pkgconfig(xproto) >= 7.0.17 BuildRequires: pkgconfig(xtrans) >= 1.2.2 %if 0%{?suse_version} >= 1315 Requires(post): update-alternatives Requires(postun): update-alternatives %endif Url: http://tigervnc.org/ BuildRoot: %{_tmppath}/%{name}-%{version}-build Summary: An implementation of VNC License: GPL-2.0-only AND MIT Group: System/X11/Servers/XF86_4 Source1: https://github.com/TigerVNC/tigervnc/archive/v%{version}.tar.gz Source4: 10-libvnc.conf Source5: vnc-server.susefirewall Source6: vnc-httpd.susefirewall Source7: vnc.reg Source8: vncpasswd.arg Source9: vnc.pam Source10: with-vnc-key.sh Source11: index.vnc Source12: x11vnc Source13: xvnc@.service Source14: xvnc.socket Source15: xvnc-novnc.service Source16: xvnc-novnc.socket Source17: tigervnc.firewalld Source18: tigervnc-https.firewalld Source19: xvnc.target Patch1: tigervnc-newfbsize.patch Patch2: tigervnc-clean-pressed-key-on-exit.patch Patch3: u_tigervnc-ignore-epipe-on-write.patch Patch4: n_tigervnc-date-time.patch Patch5: u_tigervnc-cve-2014-8240.patch Patch6: u_tigervnc_update_default_vncxstartup.patch Patch7: u_build_libXvnc_as_separate_library.patch Patch8: u_tigervnc-add-autoaccept-parameter.patch Patch9: u_change-button-layout-in-ServerDialog.patch Patch10: n_correct_path_in_desktop_file.patch Patch11: U_viewer-reset-ctrl-alt-to-menu-state-on-focus.patch Patch21: 0001-Make-ZlibInStream-more-robust-against-failures.patch Patch22: 0002-Encapsulate-PixelBuffer-internal-details.patch Patch23: 0003-Restrict-PixelBuffer-dimensions-to-safe-values.patch Patch24: 0004-Add-write-protection-to-OffsetPixelBuffer.patch Patch25: 0005-Handle-empty-Tight-gradient-rects.patch Patch26: 0006-Add-unit-test-for-PixelFormat-sanity-checks.patch Patch27: 0007-Fix-depth-sanity-test-in-PixelFormat.patch Patch28: 0008-Add-sanity-checks-for-PixelFormat-shift-values.patch Patch29: 0009-Remove-unused-FixedMemOutStream.patch Patch30: 0010-Use-size_t-for-lengths-in-stream-objects.patch Patch31: 0011-Be-defensive-about-overflows-in-stream-objects.patch Patch32: 0012-Add-unit-tests-for-PixelFormat.is888-detection.patch Patch33: 0013-Handle-pixel-formats-with-odd-shift-values.patch Patch40: U_Avoid-potential-crash-when-replacing-buffer-in-Plain.patch Patch51: U_0001-Properly-store-certificate-exceptions.patch Patch52: U_0002-Properly-store-certificate-exceptions-in-Java-viewer.patch %description TigerVNC is an implementation of VNC (Virtual Network Computing), a client/server application that allows users to launch and interact with graphical applications on remote machines. TigerVNC is capable of running 3D and video applications. TigerVNC also provides extensions for advanced authentication methods and TLS encryption. %package -n xorg-x11-Xvnc Requires(post): /usr/sbin/useradd Requires(post): /usr/sbin/groupadd Requires(post): /bin/awk Requires(post): systemd %if %{use_firewalld} Requires(post): firewall-macros %endif # Needed to generate certificates Requires: windowmanager Requires: xauth Requires: xinit Requires: xkbcomp Requires: xkeyboard-config Requires: xorg-x11-fonts-core Requires: openssl(cli) # For the with-vnc-key.sh script Requires: /bin/hostname %{?systemd_requires} %ifnarch s390 s390x Recommends: xorg-x11-Xvnc-module %endif Provides: tightvnc = 1.3.9 Provides: xorg-x11-Xvnc:/usr/lib/vnc/with-vnc-key.sh Obsoletes: tightvnc < 1.3.9 Summary: TigerVNC implementation of Xvnc Group: System/X11/Servers/XF86_4 %description -n xorg-x11-Xvnc This is the TigerVNC implementation of Xvnc. %ifnarch s390 s390x %package -n xorg-x11-Xvnc-module Requires: xorg-x11-Xvnc Summary: VNC module for X server Group: System/X11/Servers/XF86_4 %{x11_abi_extension_req} %description -n xorg-x11-Xvnc-module This module allows to share content of X server's screen over VNC. It is loaded into X server as a module if enable in X server's configuration. %endif %package -n xorg-x11-Xvnc-novnc Requires: novnc Requires: python3-websockify Requires: xorg-x11-Xvnc %{?systemd_requires} Summary: NoVNC service for Xvnc Group: System/X11/Servers/XF86_4 BuildArch: noarch %description -n xorg-x11-Xvnc-novnc A service that starts noVNC linked to Xvnc server. %package -n xorg-x11-Xvnc-java BuildArch: noarch %{?systemd_requires} Summary: VNC viewer in java Group: System/X11/Servers/XF86_4 %description -n xorg-x11-Xvnc-java A VNC client written in java that can be used as standalone application or as an applet inside web page. %package -n libXvnc1 Summary: X extension to control VNC module Group: System/Libraries %description -n libXvnc1 Xvnc extension allows X clients to read and change VNC configuration. %package -n libXvnc-devel Summary: X extension to control VNC module Group: Development/Libraries/C and C++ Requires: libXvnc1 = %version %description -n libXvnc-devel Xvnc extension allows X clients to read and change VNC configuration. %package x11vnc Summary: Wrapper that starts x0vncserver Group: System/X11/Servers/XF86_4 Requires: python Requires: xorg-x11-Xvnc Provides: x11vnc Conflicts: x11vnc BuildArch: noarch %description x11vnc This is a wrapper that looks like x11vnc, but starts x0vncserver instead. It maps common x11vnc arguments to x0vncserver arguments. %prep %setup -T -b1 -q cp -r /usr/src/xserver/* unix/xserver/ %patch1 -p1 %patch2 -p1 %patch3 -p0 %patch4 -p1 %patch5 -p1 %patch6 -p1 %patch7 -p1 %patch9 -p1 %patch10 -p1 %patch11 -p1 %patch21 -p1 %patch22 -p1 %patch23 -p1 %patch24 -p1 %patch25 -p1 %patch26 -p1 %patch27 -p1 %patch28 -p1 %patch29 -p1 %patch30 -p1 %patch31 -p1 %patch32 -p1 %patch33 -p1 %patch40 -p1 %patch51 -p1 %patch52 -p1 %patch8 -p1 pushd unix/xserver patch -p1 < ../xserver120.patch popd %build export CXXFLAGS="%optflags" export CFLAGS="%optflags" # Build all tigervnc cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_INSTALL_PREFIX:PATH=%{_prefix} -DCMAKE_BUILD_TYPE=RelWithDebInfo make %{?_smp_mflags} # Build Xvnc server pushd unix/xserver autoreconf -fi %configure \ --disable-xorg --disable-xnest --disable-xvfb --disable-dmx \ --disable-xwin --disable-xephyr --disable-kdrive --with-pic \ --disable-static --disable-xinerama \ --with-xkb-path="/usr/share/X11/xkb" \ --with-xkb-output="/var/lib/xkb/compiled" \ --enable-glx --enable-dri \ %ifnarch s390 s390x --enable-dri2 \ %endif --disable-config-dbus \ --disable-config-hal \ --disable-config-udev \ --without-dtrace \ --disable-unit-tests \ --disable-devel-docs \ --with-fontrootdir=/usr/share/fonts \ --disable-selective-werror make %{?_smp_mflags} V=1 popd # Build java client pushd java cmake -DCMAKE_INSTALL_PREFIX:PATH=%{_prefix} -DJAVACFLAGS="-encoding utf8 -source 1.6 -target 1.6" make %{?_smp_mflags} popd %install %make_install mv $RPM_BUILD_ROOT/usr/bin/vncviewer $RPM_BUILD_ROOT/usr/bin/vncviewer-tigervnc mv $RPM_BUILD_ROOT/usr/share/man/man1/vncviewer.1 $RPM_BUILD_ROOT/usr/share/man/man1/vncviewer-tigervnc.1 pushd unix/xserver %make_install popd pushd java mkdir -p $RPM_BUILD_ROOT%{_datadir}/vnc/classes install -m755 VncViewer.jar $RPM_BUILD_ROOT%{_datadir}/vnc/classes popd %ifnarch s390x install -D -m 644 %{SOURCE4} $RPM_BUILD_ROOT/etc/X11/xorg.conf.d/10-libvnc.conf %endif %if %{use_firewalld} install -D -m 644 %{SOURCE17} $RPM_BUILD_ROOT%{_libexecdir}/firewalld/services/tigervnc.xml install -D -m 644 %{SOURCE18} $RPM_BUILD_ROOT%{_libexecdir}/firewalld/services/tigervnc-https.xml %else install -D -m 644 %{SOURCE5} $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/vnc-server install -D -m 644 %{SOURCE6} $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/vnc-httpd %endif install -D -m 644 %{SOURCE7} $RPM_BUILD_ROOT/etc/slp.reg.d/vnc.reg install -D -m 755 %{SOURCE8} $RPM_BUILD_ROOT%{_bindir}/vncpasswd.arg install -D -m 644 %{SOURCE9} $RPM_BUILD_ROOT/etc/pam.d/vnc install -D -m 644 %{SOURCE11} $RPM_BUILD_ROOT%{_datadir}/vnc/classes %if 0%{?suse_version} >= 1315 ln -s -f %{_sysconfdir}/alternatives/vncviewer $RPM_BUILD_ROOT%{_bindir}/vncviewer ln -s -f %{_sysconfdir}/alternatives/vncviewer.1.gz $RPM_BUILD_ROOT%{_mandir}/man1/vncviewer.1.gz %endif mkdir -p %{buildroot}%{_sbindir} ln -sf %{_sbindir}/service %{buildroot}%{_sbindir}/rcxvnc ln -sf %{_sbindir}/service %{buildroot}%{_sbindir}/rcxvnc-novnc mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/vnc mkdir -p $RPM_BUILD_ROOT%{_libexecdir}/vnc install -D -m 755 %{SOURCE10} $RPM_BUILD_ROOT%{_libexecdir}/vnc install -D -m 755 %{SOURCE12} $RPM_BUILD_ROOT%{_bindir}/x11vnc install -D %{SOURCE13} -m 0444 %{buildroot}%{_unitdir}/xvnc@.service install -D %{SOURCE14} -m 0444 %{buildroot}%{_unitdir}/xvnc.socket install -D %{SOURCE15} -m 0444 %{buildroot}%{_unitdir}/xvnc-novnc.service install -D %{SOURCE16} -m 0444 %{buildroot}%{_unitdir}/xvnc-novnc.socket install -D %{SOURCE19} -m 0444 %{buildroot}%{_unitdir}/xvnc.target rm -rf $RPM_BUILD_ROOT/usr/share/doc/tigervnc-* %find_lang '%{name}' %post %if 0%{?suse_version} >= 1315 %_sbindir/update-alternatives \ --install %{_bindir}/vncviewer vncviewer %{_bindir}/vncviewer-tigervnc 20 \ --slave %{_mandir}/man1/vncviewer.1.gz vncviewer.1.gz %{_mandir}/man1/vncviewer-tigervnc.1.gz %endif %postun %if 0%{?suse_version} >= 1315 if [ "$1" = 0 ] ; then "%_sbindir/update-alternatives" --remove vncviewer /usr/bin/vncviewer-tigervnc fi %endif %pre -n xorg-x11-Xvnc %service_add_pre xvnc.socket getent group %{vncgroup} > /dev/null || groupadd -r %{vncgroup} || : getent passwd %{vncuser} > /dev/null || useradd -r -g %{vncgroup} -d /var/lib/empty -s /sbin/nologin -c "user for VNC" %{vncuser} || : usermod -G shadow -a %{vncuser} || : %post -n xorg-x11-Xvnc %service_add_post xvnc.socket %if %{use_firewalld} %{firewalld_reload} %endif # If there is old xinetd configuration file and VNC service was enabled, enable the systemd service too. # Once we are done, RPM will rename the file to /etc/xinetd.d/vnc.rpmsave, so this won't happen # during future updates. if [ -e /etc/xinetd.d/vnc ] && awk ' BEGIN { in_vnc1_section = 0 } /service.*vnc1/ { in_vnc1_section = 1 } in_vnc1_section && /disable\s*=\s*yes/ { exit 1 } in_vnc1_section && /}/ { exit 0 } ' /etc/xinetd.d/vnc; then echo "Found old xinetd configuration with enabled VNC service. Enabling xvnc.socket." systemctl enable xvnc.socket fi %preun -n xorg-x11-Xvnc %service_del_preun xvnc.socket %postun -n xorg-x11-Xvnc %service_del_postun xvnc.socket %pre -n xorg-x11-Xvnc-novnc %service_add_pre xvnc-novnc.service %service_add_pre xvnc-novnc.socket %post -n xorg-x11-Xvnc-novnc %service_add_post xvnc-novnc.service %service_add_post xvnc-novnc.socket %preun -n xorg-x11-Xvnc-novnc %service_del_preun xvnc-novnc.service %service_del_preun xvnc-novnc.socket %postun -n xorg-x11-Xvnc-novnc %service_del_postun xvnc-novnc.service %service_del_postun xvnc-novnc.socket %post -n libXvnc1 -p /sbin/ldconfig %postun -n libXvnc1 -p /sbin/ldconfig %files -f %{name}.lang %defattr(-,root,root,-) %ghost %{_bindir}/vncviewer %{_bindir}/vncviewer-tigervnc %doc LICENCE.TXT README.rst %ghost %_mandir/man1/vncviewer.1.gz %doc %_mandir/man1/vncviewer-tigervnc.1.gz %if 0%{?suse_version} >= 1315 %ghost %_sysconfdir/alternatives/vncviewer %ghost %_sysconfdir/alternatives/vncviewer.1.gz %endif %dir %_datadir/icons/hicolor/16x16 %dir %_datadir/icons/hicolor/16x16/apps %dir %_datadir/icons/hicolor/22x22 %dir %_datadir/icons/hicolor/22x22/apps %dir %_datadir/icons/hicolor/24x24 %dir %_datadir/icons/hicolor/24x24/apps %dir %_datadir/icons/hicolor/32x32 %dir %_datadir/icons/hicolor/32x32/apps %dir %_datadir/icons/hicolor/48x48 %dir %_datadir/icons/hicolor/48x48/apps %dir %_datadir/icons/hicolor/scalable %dir %_datadir/icons/hicolor/scalable/apps %_datadir/icons/hicolor/*/apps/tigervnc.png %_datadir/icons/hicolor/scalable/apps/tigervnc.svg %_datadir/applications/vncviewer.desktop %files -n xorg-x11-Xvnc %doc LICENCE.TXT README.rst %defattr(-,root,root) %{_bindir}/Xvnc %{_bindir}/vncconfig %{_bindir}/vncpasswd %{_bindir}/vncpasswd.arg %{_bindir}/vncserver %{_bindir}/x0vncserver %exclude %{_mandir}/man1/Xserver.1* %{_mandir}/man1/Xvnc.1* %{_mandir}/man1/vncconfig.1* %{_mandir}/man1/vncpasswd.1* %{_mandir}/man1/vncserver.1* %{_mandir}/man1/x0vncserver.1* %{_unitdir}/xvnc@.service %{_unitdir}/xvnc.socket %{_unitdir}/xvnc.target %{_sbindir}/rcxvnc %exclude /var/lib/xkb/compiled/README.compiled %if %{use_firewalld} %dir %{_libexecdir}/firewalld %dir %{_libexecdir}/firewalld/services %{_libexecdir}/firewalld/services/tigervnc.xml %{_libexecdir}/firewalld/services/tigervnc-https.xml %else %config %{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/vnc-server %config %{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/vnc-httpd %endif %dir /etc/slp.reg.d %config(noreplace) /etc/slp.reg.d/vnc.reg %config %{_sysconfdir}/pam.d/vnc %dir %attr(0755,%{vncuser},%{vncuser}) %{_sysconfdir}/vnc %ghost %attr(0600,%{vncuser},%{vncuser}) %config(noreplace) %{tlskey} %ghost %attr(0644,%{vncuser},%{vncuser}) %config(noreplace) %{tlscert} %{_libexecdir}/vnc %ifarch s390 s390x # These would be in xorg-x11-Xvnc-module, but we don't build that on s390 %exclude /usr/%{_lib}/xorg/protocol.txt %exclude /usr/%{_lib}/xorg/modules/extensions/libvnc.la %exclude /usr/%{_lib}/xorg/modules/extensions/libvnc.so %endif %ifnarch s390 s390x %files -n xorg-x11-Xvnc-module %exclude /usr/%{_lib}/xorg/protocol.txt %exclude /usr/%{_lib}/xorg/modules/extensions/libvnc.la %{_libdir}/xorg/modules/extensions/libvnc.so %config(noreplace) /etc/X11/xorg.conf.d/10-libvnc.conf %endif %files -n xorg-x11-Xvnc-novnc %{_unitdir}/xvnc-novnc.service %{_unitdir}/xvnc-novnc.socket %{_sbindir}/rcxvnc-novnc %files -n xorg-x11-Xvnc-java %doc java/com/tigervnc/vncviewer/README %{_datadir}/vnc %files -n libXvnc1 %defattr(-,root,root) %{_libdir}/libXvnc.so.1* %files -n libXvnc-devel %defattr(-,root,root) %{_libdir}/libXvnc.so %{_includedir}/X11/extensions/Xvnc.h %files x11vnc %defattr(-,root,root) %{_bindir}/x11vnc %changelog ++++++ 0001-Make-ZlibInStream-more-robust-against-failures.patch ++++++ >From d61a767d6842b530ffb532ddd5a3d233119aad40 Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Tue, 10 Sep 2019 11:05:48 +0200 Subject: [PATCH] Make ZlibInStream more robust against failures Move the checks around to avoid missing cases where we might access memory that is no longer valid. Also avoid touching the underlying stream implicitly (e.g. via the destructor) as it might also no longer be valid. A malicious server could theoretically use this for remote code execution in the client. Issue found by Pavel Cheremushkin from Kaspersky Lab --- common/rdr/ZlibInStream.cxx | 13 +++++++------ common/rdr/ZlibInStream.h | 2 +- common/rfb/CMsgReader.cxx | 3 ++- common/rfb/SMsgReader.cxx | 3 ++- common/rfb/TightDecoder.cxx | 3 ++- common/rfb/zrleDecode.h | 3 ++- 6 files changed, 16 insertions(+), 11 deletions(-) Index: tigervnc-1.9.0/common/rdr/ZlibInStream.cxx =================================================================== --- tigervnc-1.9.0.orig/common/rdr/ZlibInStream.cxx +++ tigervnc-1.9.0/common/rdr/ZlibInStream.cxx @@ -52,16 +52,16 @@ int ZlibInStream::pos() return offset + ptr - start; } -void ZlibInStream::removeUnderlying() +void ZlibInStream::flushUnderlying() { ptr = end = start; - if (!underlying) return; while (bytesIn > 0) { decompress(true); end = start; // throw away any data } - underlying = 0; + + setUnderlying(NULL, 0); } void ZlibInStream::reset() @@ -90,7 +90,7 @@ void ZlibInStream::init() void ZlibInStream::deinit() { assert(zs != NULL); - removeUnderlying(); + setUnderlying(NULL, 0); inflateEnd(zs); delete zs; zs = NULL; @@ -100,8 +100,6 @@ int ZlibInStream::overrun(int itemSize, { if (itemSize > bufSize) throw Exception("ZlibInStream overrun: max itemSize exceeded"); - if (!underlying) - throw Exception("ZlibInStream overrun: no underlying stream"); if (end - ptr != 0) memmove(start, ptr, end - ptr); @@ -127,6 +125,9 @@ int ZlibInStream::overrun(int itemSize, bool ZlibInStream::decompress(bool wait) { + if (!underlying) + throw Exception("ZlibInStream overrun: no underlying stream"); + zs->next_out = (U8*)end; zs->avail_out = start + bufSize - end; Index: tigervnc-1.9.0/common/rdr/ZlibInStream.h =================================================================== --- tigervnc-1.9.0.orig/common/rdr/ZlibInStream.h +++ tigervnc-1.9.0/common/rdr/ZlibInStream.h @@ -38,7 +38,7 @@ namespace rdr { virtual ~ZlibInStream(); void setUnderlying(InStream* is, int bytesIn); - void removeUnderlying(); + void flushUnderlying(); int pos(); void reset(); Index: tigervnc-1.9.0/common/rfb/TightDecoder.cxx =================================================================== --- tigervnc-1.9.0.orig/common/rfb/TightDecoder.cxx +++ tigervnc-1.9.0/common/rfb/TightDecoder.cxx @@ -340,7 +340,8 @@ void TightDecoder::decodeRect(const Rect zis[streamId].readBytes(netbuf, dataSize); - zis[streamId].removeUnderlying(); + zis[streamId].flushUnderlying(); + zis[streamId].setUnderlying(NULL, 0); delete ms; bufptr = netbuf; Index: tigervnc-1.9.0/common/rfb/zrleDecode.h =================================================================== --- tigervnc-1.9.0.orig/common/rfb/zrleDecode.h +++ tigervnc-1.9.0/common/rfb/zrleDecode.h @@ -178,7 +178,8 @@ void ZRLE_DECODE (const Rect& r, rdr::In } } - zis->removeUnderlying(); + zis->flushUnderlying(); + zis->setUnderlying(NULL, 0); } #undef ZRLE_DECODE ++++++ 0002-Encapsulate-PixelBuffer-internal-details.patch ++++++ >From 53f913a76196c7357d4858bfbf2c33caa9181bae Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Tue, 10 Sep 2019 15:18:30 +0200 Subject: [PATCH] Encapsulate PixelBuffer internal details Don't allow subclasses to just override dimensions or buffer details directly and instead force them to go via methods. This allows us to do sanity checks on the new values and catch bugs and attacks. --- common/rfb/Cursor.cxx | 3 +- common/rfb/EncodeManager.cxx | 5 +- common/rfb/PixelBuffer.cxx | 103 +++++++++++++++++++++------------- common/rfb/PixelBuffer.h | 17 ++++-- unix/x0vncserver/XPixelBuffer.cxx | 9 +-- unix/xserver/hw/vnc/XserverDesktop.cc | 24 ++++---- unix/xserver/hw/vnc/XserverDesktop.h | 2 +- vncviewer/PlatformPixelBuffer.cxx | 9 ++- win/rfb_win32/DIBSectionBuffer.cxx | 41 ++++++-------- 9 files changed, 111 insertions(+), 102 deletions(-) Index: tigervnc-1.9.0/common/rfb/Cursor.cxx =================================================================== --- tigervnc-1.9.0.orig/common/rfb/Cursor.cxx +++ tigervnc-1.9.0/common/rfb/Cursor.cxx @@ -271,8 +271,7 @@ void RenderedCursor::update(PixelBuffer* assert(cursor); format = framebuffer->getPF(); - width_ = framebuffer->width(); - height_ = framebuffer->height(); + setSize(framebuffer->width(), framebuffer->height()); rawOffset = pos.subtract(cursor->hotspot()); clippedRect = Rect(0, 0, cursor->width(), cursor->height()) Index: tigervnc-1.9.0/common/rfb/EncodeManager.cxx =================================================================== --- tigervnc-1.9.0.orig/common/rfb/EncodeManager.cxx +++ tigervnc-1.9.0/common/rfb/EncodeManager.cxx @@ -979,11 +979,8 @@ void EncodeManager::OffsetPixelBuffer::u int stride_) { format = pf; - width_ = width; - height_ = height; // Forced cast. We never write anything though, so it should be safe. - data = (rdr::U8*)data_; - stride = stride_; + setBuffer(width, height, (rdr::U8*)data_, stride_); } // Preprocessor generated, optimised methods Index: tigervnc-1.9.0/common/rfb/PixelBuffer.cxx =================================================================== --- tigervnc-1.9.0.orig/common/rfb/PixelBuffer.cxx +++ tigervnc-1.9.0/common/rfb/PixelBuffer.cxx @@ -35,8 +35,14 @@ static LogWriter vlog("PixelBuffer"); // -=- Generic pixel buffer class PixelBuffer::PixelBuffer(const PixelFormat& pf, int w, int h) - : format(pf), width_(w), height_(h) {} -PixelBuffer::PixelBuffer() : width_(0), height_(0) {} + : format(pf), width_(0), height_(0) +{ + setSize(w, h); +} + +PixelBuffer::PixelBuffer() : width_(0), height_(0) +{ +} PixelBuffer::~PixelBuffer() {} @@ -53,7 +59,7 @@ PixelBuffer::getImage(void* imageBuf, co if (!r.enclosed_by(getRect())) throw rfb::Exception("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d", r.width(), r.height(), - r.tl.x, r.tl.y, width_, height_); + r.tl.x, r.tl.y, width(), height()); data = getBuffer(r, &inStride); @@ -89,7 +95,7 @@ void PixelBuffer::getImage(const PixelFo if (!r.enclosed_by(getRect())) throw rfb::Exception("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d", r.width(), r.height(), - r.tl.x, r.tl.y, width_, height_); + r.tl.x, r.tl.y, width(), height()); if (stride == 0) stride = r.width(); @@ -100,6 +106,12 @@ void PixelBuffer::getImage(const PixelFo stride, srcStride); } +void PixelBuffer::setSize(int width, int height) +{ + width_ = width; + height_ = height; +} + // -=- Modifiable generic pixel buffer class ModifiablePixelBuffer::ModifiablePixelBuffer(const PixelFormat& pf, @@ -124,7 +136,7 @@ void ModifiablePixelBuffer::fillRect(con if (!r.enclosed_by(getRect())) throw rfb::Exception("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", - r.width(), r.height(), r.tl.x, r.tl.y, width_, height_); + r.width(), r.height(), r.tl.x, r.tl.y, width(), height()); w = r.width(); h = r.height(); @@ -175,7 +187,7 @@ void ModifiablePixelBuffer::imageRect(co if (!r.enclosed_by(getRect())) throw rfb::Exception("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", r.width(), r.height(), - r.tl.x, r.tl.y, width_, height_); + r.tl.x, r.tl.y, width(), height()); bytesPerPixel = getPF().bpp/8; @@ -213,13 +225,13 @@ void ModifiablePixelBuffer::copyRect(con if (!drect.enclosed_by(getRect())) throw rfb::Exception("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", drect.width(), drect.height(), - drect.tl.x, drect.tl.y, width_, height_); + drect.tl.x, drect.tl.y, width(), height()); srect = drect.translate(move_by_delta.negate()); if (!srect.enclosed_by(getRect())) throw rfb::Exception("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d", srect.width(), srect.height(), - srect.tl.x, srect.tl.y, width_, height_); + srect.tl.x, srect.tl.y, width(), height()); srcData = getBuffer(srect, &srcStride); dstData = getBufferRW(drect, &dstStride); @@ -272,7 +284,7 @@ void ModifiablePixelBuffer::imageRect(co if (!dest.enclosed_by(getRect())) throw rfb::Exception("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", dest.width(), dest.height(), - dest.tl.x, dest.tl.y, width_, height_); + dest.tl.x, dest.tl.y, width(), height()); if (stride == 0) stride = dest.width(); @@ -301,7 +313,7 @@ rdr::U8* FullFramePixelBuffer::getBuffer if (!r.enclosed_by(getRect())) throw rfb::Exception("Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d", r.width(), r.height(), - r.tl.x, r.tl.y, width_, height_); + r.tl.x, r.tl.y, width(), height()); *stride_ = stride; return &data[(r.tl.x + (r.tl.y * stride)) * format.bpp/8]; @@ -316,55 +328,67 @@ const rdr::U8* FullFramePixelBuffer::get if (!r.enclosed_by(getRect())) throw rfb::Exception("Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d", r.width(), r.height(), - r.tl.x, r.tl.y, width_, height_); + r.tl.x, r.tl.y, width(), height()); *stride_ = stride; return &data[(r.tl.x + (r.tl.y * stride)) * format.bpp/8]; } +void FullFramePixelBuffer::setBuffer(int width, int height, + rdr::U8* data_, int stride_) +{ + ModifiablePixelBuffer::setSize(width, height); + stride = stride_; + data = data_; +} + +void FullFramePixelBuffer::setSize(int w, int h) +{ + // setBuffer() should be used + throw rfb::Exception("Invalid call to FullFramePixelBuffer::setSize()"); +} + // -=- Managed pixel buffer class // Automatically allocates enough space for the specified format & area ManagedPixelBuffer::ManagedPixelBuffer() - : datasize(0) + : data_(NULL), datasize(0) { - checkDataSize(); -}; +} ManagedPixelBuffer::ManagedPixelBuffer(const PixelFormat& pf, int w, int h) - : FullFramePixelBuffer(pf, w, h, NULL, w), datasize(0) + : FullFramePixelBuffer(pf, 0, 0, NULL, 0), data_(NULL), datasize(0) { - checkDataSize(); -}; - -ManagedPixelBuffer::~ManagedPixelBuffer() { - if (data) delete [] data; -}; - + setSize(w, h); +} -void -ManagedPixelBuffer::setPF(const PixelFormat &pf) { - format = pf; checkDataSize(); -}; -void -ManagedPixelBuffer::setSize(int w, int h) { - width_ = w; height_ = h; stride = w; checkDataSize(); -}; +ManagedPixelBuffer::~ManagedPixelBuffer() +{ + if (data_) + delete [] data_; +} +void ManagedPixelBuffer::setPF(const PixelFormat &pf) +{ + format = pf; + setSize(width(), height()); +} + +void ManagedPixelBuffer::setSize(int w, int h) +{ + unsigned long new_datasize = w * h * (format.bpp/8); -inline void -ManagedPixelBuffer::checkDataSize() { - unsigned long new_datasize = width_ * height_ * (format.bpp/8); + new_datasize = w * h * (format.bpp/8); if (datasize < new_datasize) { - if (data) { - delete [] data; - datasize = 0; data = 0; + if (data_) { + delete [] data_; + data_ = NULL; + datasize = 0; } if (new_datasize) { - data = new U8[new_datasize]; - if (!data) - throw Exception("rfb::ManagedPixelBuffer unable to allocate buffer"); + data_ = new U8[new_datasize]; datasize = new_datasize; } } + setBuffer(w, h, data_, w); }; Index: tigervnc-1.9.0/common/rfb/PixelBuffer.h =================================================================== --- tigervnc-1.9.0.orig/common/rfb/PixelBuffer.h +++ tigervnc-1.9.0/common/rfb/PixelBuffer.h @@ -90,7 +90,12 @@ namespace rfb { protected: PixelBuffer(); + virtual void setSize(int width, int height); + + protected: PixelFormat format; + + private: int width_, height_; }; @@ -154,7 +159,12 @@ namespace rfb { protected: FullFramePixelBuffer(); + virtual void setBuffer(int width, int height, rdr::U8* data, int stride); + private: + virtual void setSize(int w, int h); + + private: rdr::U8* data; int stride; }; @@ -172,12 +182,9 @@ namespace rfb { virtual void setPF(const PixelFormat &pf); virtual void setSize(int w, int h); - // Return the total number of bytes of pixel data in the buffer - int dataLen() const { return width_ * height_ * (format.bpp/8); } - - protected: + private: + rdr::U8* data_; // Mirrors FullFramePixelBuffer::data unsigned long datasize; - void checkDataSize(); }; }; Index: tigervnc-1.9.0/unix/x0vncserver/XPixelBuffer.cxx =================================================================== --- tigervnc-1.9.0.orig/unix/x0vncserver/XPixelBuffer.cxx +++ tigervnc-1.9.0/unix/x0vncserver/XPixelBuffer.cxx @@ -50,13 +50,8 @@ XPixelBuffer::XPixelBuffer(Display *dpy, ffs(m_image->xim->blue_mask) - 1); // Set up the remaining data of the parent class. - width_ = rect.width(); - height_ = rect.height(); - data = (rdr::U8 *)m_image->xim->data; - - // Calculate the distance in pixels between two subsequent scan - // lines of the framebuffer. This may differ from image width. - stride = m_image->xim->bytes_per_line * 8 / m_image->xim->bits_per_pixel; + setBuffer(rect.width(), rect.height(), (rdr::U8 *)m_image->xim->data, + m_image->xim->bytes_per_line * 8 / m_image->xim->bits_per_pixel); // Get initial screen image from the X display. m_image->get(DefaultRootWindow(m_dpy), m_offsetLeft, m_offsetTop); Index: tigervnc-1.9.0/unix/xserver/hw/vnc/XserverDesktop.cc =================================================================== --- tigervnc-1.9.0.orig/unix/xserver/hw/vnc/XserverDesktop.cc +++ tigervnc-1.9.0/unix/xserver/hw/vnc/XserverDesktop.cc @@ -115,7 +115,7 @@ XserverDesktop::XserverDesktop(int scree : screenIndex(screenIndex_), server(0), httpServer(0), listeners(listeners_), httpListeners(httpListeners_), - directFbptr(true), + shadowFramebuffer(NULL), queryConnectId(0), queryConnectTimer(this) { format = pf; @@ -152,8 +152,8 @@ XserverDesktop::~XserverDesktop() delete httpListeners.back(); httpListeners.pop_back(); } - if (!directFbptr) - delete [] data; + if (shadowFramebuffer) + delete [] shadowFramebuffer; delete httpServer; delete server; } @@ -172,22 +172,18 @@ void XserverDesktop::setFramebuffer(int { ScreenSet layout; - width_ = w; - height_ = h; - - if (!directFbptr) { - delete [] data; - directFbptr = true; + if (shadowFramebuffer) { + delete [] shadowFramebuffer; + shadowFramebuffer = NULL; } if (!fbptr) { - fbptr = new rdr::U8[w * h * (format.bpp/8)]; + shadowFramebuffer = new rdr::U8[w * h * (format.bpp/8)]; + fbptr = shadowFramebuffer; stride_ = w; - directFbptr = false; } - data = (rdr::U8*)fbptr; - stride = stride_; + setBuffer(w, h, (rdr::U8*)fbptr, stride_); vncSetGlueContext(screenIndex); layout = ::computeScreenLayout(&outputIdMap); @@ -569,7 +565,7 @@ unsigned int XserverDesktop::setScreenLa void XserverDesktop::grabRegion(const rfb::Region& region) { - if (directFbptr) + if (shadowFramebuffer == NULL) return; std::vector<rfb::Rect> rects; Index: tigervnc-1.9.0/unix/xserver/hw/vnc/XserverDesktop.h =================================================================== --- tigervnc-1.9.0.orig/unix/xserver/hw/vnc/XserverDesktop.h +++ tigervnc-1.9.0/unix/xserver/hw/vnc/XserverDesktop.h @@ -124,7 +124,7 @@ private: rfb::HTTPServer* httpServer; std::list<network::SocketListener*> listeners; std::list<network::SocketListener*> httpListeners; - bool directFbptr; + rdr::U8* shadowFramebuffer; uint32_t queryConnectId; network::Socket* queryConnectSocket; Index: tigervnc-1.9.0/vncviewer/PlatformPixelBuffer.cxx =================================================================== --- tigervnc-1.9.0.orig/vncviewer/PlatformPixelBuffer.cxx +++ tigervnc-1.9.0/vncviewer/PlatformPixelBuffer.cxx @@ -36,7 +36,7 @@ static rfb::LogWriter vlog("PlatformPixe PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) : FullFramePixelBuffer(rfb::PixelFormat(32, 24, false, true, 255, 255, 255, 16, 8, 0), - width, height, 0, stride), + 0, 0, NULL, 0), Surface(width, height) #if !defined(WIN32) && !defined(__APPLE__) , shminfo(NULL), xim(NULL) @@ -56,11 +56,10 @@ PlatformPixelBuffer::PlatformPixelBuffer vlog.debug("Using standard XImage"); } - data = (rdr::U8*)xim->data; - stride = xim->bytes_per_line / (getPF().bpp/8); + setBuffer(width, height, (rdr::U8*)xim->data, + xim->bytes_per_line / (getPF().bpp/8)); #else - FullFramePixelBuffer::data = (rdr::U8*)Surface::data; - stride = width; + setBuffer(width, height, (rdr::U8*)Surface::data, width); #endif } Index: tigervnc-1.9.0/win/rfb_win32/DIBSectionBuffer.cxx =================================================================== --- tigervnc-1.9.0.orig/win/rfb_win32/DIBSectionBuffer.cxx +++ tigervnc-1.9.0/win/rfb_win32/DIBSectionBuffer.cxx @@ -52,39 +52,28 @@ void DIBSectionBuffer::setPF(const Pixel if (!pf.trueColour) throw rfb::Exception("palette format not supported"); format = pf; - recreateBuffer(); + setSize(width(), height()); } -void DIBSectionBuffer::setSize(int w, int h) { - if (width_ == w && height_ == h) { - vlog.debug("size unchanged by setSize()"); - return; - } - width_ = w; - height_ = h; - recreateBuffer(); -} - - inline void initMaxAndShift(DWORD mask, int* max, int* shift) { for ((*shift) = 0; (mask & 1) == 0; (*shift)++) mask >>= 1; (*max) = (rdr::U16)mask; } -void DIBSectionBuffer::recreateBuffer() { +void DIBSectionBuffer::setSize(int w, int h) { HBITMAP new_bitmap = 0; rdr::U8* new_data = 0; - if (width_ && height_ && (format.depth != 0)) { + if (w && h && (format.depth != 0)) { BitmapInfo bi; memset(&bi, 0, sizeof(bi)); UINT iUsage = DIB_RGB_COLORS; bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biBitCount = format.bpp; - bi.bmiHeader.biSizeImage = (format.bpp / 8) * width_ * height_; + bi.bmiHeader.biSizeImage = (format.bpp / 8) * w * h; bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biWidth = width_; - bi.bmiHeader.biHeight = -height_; + bi.bmiHeader.biWidth = w; + bi.bmiHeader.biHeight = -h; bi.bmiHeader.biCompression = (format.bpp > 8) ? BI_BITFIELDS : BI_RGB; bi.mask.red = format.pixelFromRGB((rdr::U16)~0, 0, 0); bi.mask.green = format.pixelFromRGB(0, (rdr::U16)~0, 0); @@ -115,12 +104,12 @@ void DIBSectionBuffer::recreateBuffer() if (device) { BitmapDC src_dev(device, bitmap); BitmapDC dest_dev(device, new_bitmap); - BitBlt(dest_dev, 0, 0, width_, height_, src_dev, 0, 0, SRCCOPY); + BitBlt(dest_dev, 0, 0, w, h, src_dev, 0, 0, SRCCOPY); } else { WindowDC wndDC(window); BitmapDC src_dev(wndDC, bitmap); BitmapDC dest_dev(wndDC, new_bitmap); - BitBlt(dest_dev, 0, 0, width_, height_, src_dev, 0, 0, SRCCOPY); + BitBlt(dest_dev, 0, 0, w, h, src_dev, 0, 0, SRCCOPY); } } @@ -128,17 +117,17 @@ void DIBSectionBuffer::recreateBuffer() // Delete the old bitmap DeleteObject(bitmap); bitmap = 0; - data = 0; + setBuffer(0, 0, NULL, 0); } if (new_bitmap) { int bpp, depth; int redMax, greenMax, blueMax; int redShift, greenShift, blueShift; + int new_stride; // Set up the new bitmap bitmap = new_bitmap; - data = new_data; // Determine the *actual* DIBSection format DIBSECTION ds; @@ -147,14 +136,16 @@ void DIBSectionBuffer::recreateBuffer() // Correct the "stride" of the DIB // *** This code DWORD aligns each row - is that right??? - stride = width_; - int bytesPerRow = stride * format.bpp/8; + new_stride = w; + int bytesPerRow = new_stride * format.bpp/8; if (bytesPerRow % 4) { bytesPerRow += 4 - (bytesPerRow % 4); - stride = (bytesPerRow * 8) / format.bpp; - vlog.info("adjusting DIB stride: %d to %d", width_, stride); + new_stride = (bytesPerRow * 8) / format.bpp; + vlog.info("adjusting DIB stride: %d to %d", w, new_stride); } + setBuffer(w, h, new_data, new_stride); + // Calculate the PixelFormat for the DIB bpp = depth = ds.dsBm.bmBitsPixel; ++++++ 0003-Restrict-PixelBuffer-dimensions-to-safe-values.patch ++++++ >From 996356b6c65ca165ee1ea46a571c32a1dc3c3821 Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Tue, 10 Sep 2019 15:21:03 +0200 Subject: [PATCH] Restrict PixelBuffer dimensions to safe values We do a lot of calculations based on pixel coordinates and we need to make sure they do not overflow. Restrict the maximum dimensions we support rather than try to switch over all calculations to use 64 bit integers. This prevents attackers from from injecting code by specifying a huge framebuffer size and relying on the values overflowing to access invalid areas of the heap. This primarily affects the client which gets both the screen dimensions and the pixel contents from the remote side. But the server might also be affected as a client can adjust the screen dimensions, as can applications inside the session. Issue found by Pavel Cheremushkin from Kaspersky Lab. --- common/rfb/PixelBuffer.cxx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/common/rfb/PixelBuffer.cxx b/common/rfb/PixelBuffer.cxx index 0aa67744..fe406b96 100644 --- a/common/rfb/PixelBuffer.cxx +++ b/common/rfb/PixelBuffer.cxx @@ -31,6 +31,14 @@ using namespace rdr; static LogWriter vlog("PixelBuffer"); +// We do a lot of byte offset calculations that assume the result fits +// inside a signed 32 bit integer. Limit the maximum size of pixel +// buffers so that these calculations never overflow. + +const int maxPixelBufferWidth = 16384; +const int maxPixelBufferHeight = 16384; +const int maxPixelBufferStride = 16384; + // -=- Generic pixel buffer class @@ -108,6 +116,11 @@ void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf, void PixelBuffer::setSize(int width, int height) { + if ((width < 0) || (width > maxPixelBufferWidth)) + throw rfb::Exception("Invalid PixelBuffer width of %d pixels requested", width); + if ((height < 0) || (height > maxPixelBufferHeight)) + throw rfb::Exception("Invalid PixelBuffer height of %d pixels requested", height); + width_ = width; height_ = height; } @@ -340,6 +353,15 @@ const rdr::U8* FullFramePixelBuffer::getBuffer(const Rect& r, int* stride_) cons void FullFramePixelBuffer::setBuffer(int width, int height, rdr::U8* data_, int stride_) { + if ((width < 0) || (width > maxPixelBufferWidth)) + throw rfb::Exception("Invalid PixelBuffer width of %d pixels requested", width); + if ((height < 0) || (height > maxPixelBufferHeight)) + throw rfb::Exception("Invalid PixelBuffer height of %d pixels requested", height); + if ((stride_ < 0) || (stride_ > maxPixelBufferStride) || (stride_ < width)) + throw rfb::Exception("Invalid PixelBuffer stride of %d pixels requested", stride_); + if ((width != 0) && (height != 0) && (data_ == NULL)) + throw rfb::Exception("PixelBuffer requested without a valid memory area"); + ModifiablePixelBuffer::setSize(width, height); stride = stride_; data = data_; -- 2.16.4 ++++++ 0004-Add-write-protection-to-OffsetPixelBuffer.patch ++++++ >From 9f615301aba1cc54a749950bf9462c5a85217bc4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Tue, 10 Sep 2019 15:25:30 +0200 Subject: [PATCH] Add write protection to OffsetPixelBuffer No one should every try to write to this buffer. Enforce that by throwing an exception if any one tries to get a writeable pointer to the data. --- common/rfb/EncodeManager.cxx | 6 ++++++ common/rfb/EncodeManager.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx index 54f7102b..92ac5676 100644 --- a/common/rfb/EncodeManager.cxx +++ b/common/rfb/EncodeManager.cxx @@ -28,6 +28,7 @@ #include <rfb/SMsgWriter.h> #include <rfb/UpdateTracker.h> #include <rfb/LogWriter.h> +#include <rfb/Exception.h> #include <rfb/RawEncoder.h> #include <rfb/RREEncoder.h> @@ -1053,6 +1054,11 @@ void EncodeManager::OffsetPixelBuffer::update(const PixelFormat& pf, setBuffer(width, height, (rdr::U8*)data_, stride_); } +rdr::U8* EncodeManager::OffsetPixelBuffer::getBufferRW(const Rect& r, int* stride) +{ + throw rfb::Exception("Invalid write attempt to OffsetPixelBuffer"); +} + // Preprocessor generated, optimised methods #define BPP 8 diff --git a/common/rfb/EncodeManager.h b/common/rfb/EncodeManager.h index bdae9063..f8201c34 100644 --- a/common/rfb/EncodeManager.h +++ b/common/rfb/EncodeManager.h @@ -148,6 +148,9 @@ namespace rfb { void update(const PixelFormat& pf, int width, int height, const rdr::U8* data_, int stride); + + private: + virtual rdr::U8* getBufferRW(const Rect& r, int* stride); }; OffsetPixelBuffer offsetPixelBuffer; -- 2.16.4 ++++++ 0005-Handle-empty-Tight-gradient-rects.patch ++++++ >From b4ada8d0c6dac98c8b91fc64d112569a8ae5fb95 Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Tue, 10 Sep 2019 15:36:42 +0200 Subject: [PATCH] Handle empty Tight gradient rects We always assumed there would be one pixel per row so a rect with a zero width would result in us writing to unknown memory. This could theoretically be used by a malicious server to inject code in to the viewer process. Issue found by Pavel Cheremushkin from Kaspersky Lab. --- common/rfb/tightDecode.h | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/common/rfb/tightDecode.h b/common/rfb/tightDecode.h index b6e86ed5..8f77aebd 100644 --- a/common/rfb/tightDecode.h +++ b/common/rfb/tightDecode.h @@ -56,15 +56,17 @@ TightDecoder::FilterGradient24(const rdr::U8 *inbuf, int rectWidth = r.width(); for (y = 0; y < rectHeight; y++) { - /* First pixel in a row */ - for (c = 0; c < 3; c++) { - pix[c] = inbuf[y*rectWidth*3+c] + prevRow[c]; - thisRow[c] = pix[c]; - } - pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); + for (x = 0; x < rectWidth; x++) { + /* First pixel in a row */ + if (x == 0) { + for (c = 0; c < 3; c++) { + pix[c] = inbuf[y*rectWidth*3+c] + prevRow[c]; + thisRow[c] = pix[c]; + } + pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); + continue; + } - /* Remaining pixels of a row */ - for (x = 1; x < rectWidth; x++) { for (c = 0; c < 3; c++) { est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c]; if (est[c] > 0xff) { @@ -103,17 +105,20 @@ void TightDecoder::FilterGradient(const rdr::U8* inbuf, int rectWidth = r.width(); for (y = 0; y < rectHeight; y++) { - /* First pixel in a row */ - pf.rgbFromBuffer(pix, &inbuf[y*rectWidth], 1); - for (c = 0; c < 3; c++) - pix[c] += prevRow[c]; + for (x = 0; x < rectWidth; x++) { + /* First pixel in a row */ + if (x == 0) { + pf.rgbFromBuffer(pix, &inbuf[y*rectWidth], 1); + for (c = 0; c < 3; c++) + pix[c] += prevRow[c]; - memcpy(thisRow, pix, sizeof(pix)); + memcpy(thisRow, pix, sizeof(pix)); - pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); + pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); + + continue; + } - /* Remaining pixels of a row */ - for (x = 1; x < rectWidth; x++) { for (c = 0; c < 3; c++) { est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c]; if (est[c] > 255) { -- 2.16.4 ++++++ 0006-Add-unit-test-for-PixelFormat-sanity-checks.patch ++++++ >From 014c5012377519d7f0add23ebac077ccd882aa9f Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Tue, 10 Sep 2019 15:59:51 +0200 Subject: [PATCH] Add unit test for PixelFormat sanity checks --- common/rfb/PixelFormat.cxx | 3 +- tests/unit/CMakeLists.txt | 3 ++ tests/unit/pixelformat.cxx | 114 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 tests/unit/pixelformat.cxx Index: tigervnc-1.9.0/common/rfb/PixelFormat.cxx =================================================================== --- tigervnc-1.9.0.orig/common/rfb/PixelFormat.cxx +++ tigervnc-1.9.0/common/rfb/PixelFormat.cxx @@ -81,7 +81,8 @@ PixelFormat::PixelFormat(int b, int d, b redMax(rm), greenMax(gm), blueMax(bm), redShift(rs), greenShift(gs), blueShift(bs) { - assert(isSane()); + if (!isSane()) + throw Exception("invalid pixel format"); updateState(); } Index: tigervnc-1.9.0/tests/unit/pixelformat.cxx =================================================================== --- /dev/null +++ tigervnc-1.9.0/tests/unit/pixelformat.cxx @@ -0,0 +1,114 @@ +/* Copyright 2019 Pierre Ossman <oss...@cendio.se> for Cendio AB + * + * This 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 software 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 software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include <stdio.h> + +#include <rfb/PixelFormat.h> +#include <rfb/Exception.h> + +static void doTest(bool should_fail, int b, int d, bool e, bool t, + int rm, int gm, int bm, int rs, int gs, int bs) +{ + rfb::PixelFormat* pf; + + printf("PixelFormat(%d, %d, %s, %s, %d, %d, %d, %d, %d, %d): ", + b, d, e ? "true" : "false", t ? "true": "false", + rm, gm, bm, rs, gs, bs); + + try { + pf = new rfb::PixelFormat(b, d, e, t, rm, gm, bm, rs, gs, bs); + } catch(rfb::Exception &e) { + if (should_fail) + printf("OK"); + else + printf("FAILED"); + printf("\n"); + fflush(stdout); + return; + } + + delete pf; + + if (should_fail) + printf("FAILED"); + else + printf("OK"); + printf("\n"); + fflush(stdout); +} + +int main(int argc, char** argv) +{ + /* Normal true color formats */ + + doTest(false, 32, 24, false, true, 255, 255, 255, 0, 8, 16); + doTest(false, 32, 24, false, true, 255, 255, 255, 24, 16, 8); + + doTest(false, 16, 16, false, true, 15, 31, 15, 0, 5, 11); + + doTest(false, 8, 8, false, true, 3, 7, 3, 0, 2, 5); + + /* Excessive bpp */ + + doTest(false, 32, 16, false, true, 15, 31, 15, 0, 5, 11); + + doTest(false, 16, 16, false, true, 15, 31, 15, 0, 5, 11); + + doTest(false, 32, 8, false, true, 3, 7, 3, 0, 2, 5); + + doTest(false, 16, 8, false, true, 3, 7, 3, 0, 2, 5); + + /* Colour map */ + + doTest(false, 8, 8, false, false, 0, 0, 0, 0, 0, 0); + + /* Invalid bpp */ + + doTest(true, 64, 24, false, true, 255, 255, 255, 0, 8, 16); + + doTest(true, 18, 16, false, true, 15, 31, 15, 0, 5, 11); + + doTest(true, 3, 3, false, true, 1, 1, 1, 0, 1, 2); + + /* Invalid depth */ + + doTest(true, 16, 24, false, true, 15, 31, 15, 0, 5, 11); + + doTest(true, 8, 24, false, true, 3, 7, 3, 0, 2, 5); + doTest(true, 8, 16, false, true, 3, 7, 3, 0, 2, 5); + + doTest(true, 32, 24, false, false, 0, 0, 0, 0, 0, 0); + + /* Invalid max values */ + + doTest(true, 32, 24, false, true, 254, 255, 255, 0, 8, 16); + doTest(true, 32, 24, false, true, 255, 253, 255, 0, 8, 16); + doTest(true, 32, 24, false, true, 255, 255, 252, 0, 8, 16); + + doTest(true, 32, 24, false, true, 511, 127, 127, 0, 16, 20); + doTest(true, 32, 24, false, true, 127, 511, 127, 0, 4, 20); + doTest(true, 32, 24, false, true, 127, 127, 511, 0, 4, 8); + + /* Overlapping channels */ + + doTest(true, 32, 24, false, true, 255, 255, 255, 0, 7, 16); + doTest(true, 32, 24, false, true, 255, 255, 255, 0, 8, 15); + doTest(true, 32, 24, false, true, 255, 255, 255, 0, 16, 7); + + return 0; +} ++++++ 0007-Fix-depth-sanity-test-in-PixelFormat.patch ++++++ >From f1b9b868ec943d51ef631f53a095d48d3f178f4f Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Tue, 10 Sep 2019 16:01:44 +0200 Subject: [PATCH] Fix depth sanity test in PixelFormat --- common/rfb/PixelFormat.cxx | 2 +- tests/unit/pixelformat.cxx | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx index 0be4d1da..2d8142d1 100644 --- a/common/rfb/PixelFormat.cxx +++ b/common/rfb/PixelFormat.cxx @@ -679,7 +679,7 @@ bool PixelFormat::isSane(void) return false; totalBits = bits(redMax) + bits(greenMax) + bits(blueMax); - if (totalBits > bpp) + if (totalBits > depth) return false; if (((redMax << redShift) & (greenMax << greenShift)) != 0) diff --git a/tests/unit/pixelformat.cxx b/tests/unit/pixelformat.cxx index 4eb45281..7b6087f7 100644 --- a/tests/unit/pixelformat.cxx +++ b/tests/unit/pixelformat.cxx @@ -104,6 +104,10 @@ int main(int argc, char** argv) doTest(true, 32, 24, false, true, 127, 511, 127, 0, 4, 20); doTest(true, 32, 24, false, true, 127, 127, 511, 0, 4, 8); + /* Insufficient depth */ + + doTest(true, 32, 16, false, true, 255, 255, 255, 0, 8, 16); + /* Overlapping channels */ doTest(true, 32, 24, false, true, 255, 255, 255, 0, 7, 16); -- 2.16.4 ++++++ 0008-Add-sanity-checks-for-PixelFormat-shift-values.patch ++++++ >From cd1d650c532a46e95a1229dffaf281c76a50cdfe Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Tue, 10 Sep 2019 16:07:50 +0200 Subject: [PATCH] Add sanity checks for PixelFormat shift values Otherwise we might be tricked in to reading and writing things at incorrect offsets for pixels which ultimately could result in an attacker writing things to the stack or heap and executing things they shouldn't. This only affects the server as the client never uses the pixel format suggested by th server. Issue found by Pavel Cheremushkin from Kaspersky Lab. --- common/rfb/PixelFormat.cxx | 7 +++++++ tests/unit/pixelformat.cxx | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx index 2d8142d1..789c43ed 100644 --- a/common/rfb/PixelFormat.cxx +++ b/common/rfb/PixelFormat.cxx @@ -682,6 +682,13 @@ bool PixelFormat::isSane(void) if (totalBits > depth) return false; + if ((bits(redMax) + redShift) > bpp) + return false; + if ((bits(greenMax) + greenShift) > bpp) + return false; + if ((bits(blueMax) + blueShift) > bpp) + return false; + if (((redMax << redShift) & (greenMax << greenShift)) != 0) return false; if (((redMax << redShift) & (blueMax << blueShift)) != 0) diff --git a/tests/unit/pixelformat.cxx b/tests/unit/pixelformat.cxx index 7b6087f7..46fecfb4 100644 --- a/tests/unit/pixelformat.cxx +++ b/tests/unit/pixelformat.cxx @@ -108,6 +108,12 @@ int main(int argc, char** argv) doTest(true, 32, 16, false, true, 255, 255, 255, 0, 8, 16); + /* Invalid shift values */ + + doTest(true, 32, 24, false, true, 255, 255, 255, 25, 8, 16); + doTest(true, 32, 24, false, true, 255, 255, 255, 0, 25, 16); + doTest(true, 32, 24, false, true, 255, 255, 255, 0, 8, 25); + /* Overlapping channels */ doTest(true, 32, 24, false, true, 255, 255, 255, 0, 7, 16); -- 2.16.4 ++++++ 0009-Remove-unused-FixedMemOutStream.patch ++++++ >From 4ff58f0acaeb566b79ae12cf013b376eaaaab834 Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Mon, 23 Sep 2019 10:09:31 +0200 Subject: [PATCH] Remove unused FixedMemOutStream --- common/rdr/FixedMemOutStream.h | 52 ------------------------------------------ 1 file changed, 52 deletions(-) delete mode 100644 common/rdr/FixedMemOutStream.h diff --git a/common/rdr/FixedMemOutStream.h b/common/rdr/FixedMemOutStream.h deleted file mode 100644 index e4ec52cb..00000000 --- a/common/rdr/FixedMemOutStream.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This 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 software 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 software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -// -// A FixedMemOutStream writes to a buffer of a fixed length. -// - -#ifndef __RDR_FIXEDMEMOUTSTREAM_H__ -#define __RDR_FIXEDMEMOUTSTREAM_H__ - -#include <rdr/OutStream.h> -#include <rdr/Exception.h> - -namespace rdr { - - class FixedMemOutStream : public OutStream { - - public: - - FixedMemOutStream(void* buf, int len) { - ptr = start = (U8*)buf; - end = start + len; - } - - int length() { return ptr - start; } - void reposition(int pos) { ptr = start + pos; } - const void* data() { return (const void*)start; } - - private: - - int overrun(int itemSize, int nItems) { throw EndOfStream(); } - U8* start; - }; - -} - -#endif -- 2.16.4 ++++++ 0010-Use-size_t-for-lengths-in-stream-objects.patch ++++++ ++++ 1427 lines (skipped) ++++++ 0011-Be-defensive-about-overflows-in-stream-objects.patch ++++++ >From 75e6e0653a48baf474fd45d78b1da53e2f324642 Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Tue, 24 Sep 2019 09:41:07 +0200 Subject: [PATCH] Be defensive about overflows in stream objects We use a lot of lengths given to us over the network, so be more paranoid about them causing an overflow as otherwise an attacker might trick us in to overwriting other memory. This primarily affects the client which often gets lengths from the server, but there are also some scenarios where the server might theoretically be vulnerable. Issue found by Pavel Cheremushkin from Kaspersky Lab. --- common/rdr/FdInStream.cxx | 8 +++++--- common/rdr/FdOutStream.cxx | 7 ++++--- common/rdr/FileInStream.cxx | 8 +++++--- common/rdr/HexInStream.cxx | 8 +++++--- common/rdr/HexOutStream.cxx | 6 ++++-- common/rdr/InStream.h | 24 +++++++++++++----------- common/rdr/MemOutStream.h | 4 ++++ common/rdr/OutStream.h | 24 +++++++++++++----------- common/rdr/RandomStream.cxx | 6 ++++-- common/rdr/TLSInStream.cxx | 10 ++++++---- common/rdr/TLSOutStream.cxx | 6 ++++-- common/rdr/ZlibInStream.cxx | 6 ++++-- common/rdr/ZlibOutStream.cxx | 6 ++++-- 13 files changed, 75 insertions(+), 48 deletions(-) diff --git a/common/rdr/FdInStream.cxx b/common/rdr/FdInStream.cxx index 9e84ab7a..1730d6d1 100644 --- a/common/rdr/FdInStream.cxx +++ b/common/rdr/FdInStream.cxx @@ -136,7 +136,7 @@ size_t FdInStream::overrun(size_t itemSize, size_t nItems, bool wait) ptr = start; size_t bytes_to_read; - while (end < start + itemSize) { + while ((size_t)(end - start) < itemSize) { bytes_to_read = start + bufSize - end; if (!timing) { // When not timing, we must be careful not to read too much @@ -152,8 +152,10 @@ size_t FdInStream::overrun(size_t itemSize, size_t nItems, bool wait) end += n; } - if (itemSize * nItems > (size_t)(end - ptr)) - nItems = (end - ptr) / itemSize; + size_t nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; return nItems; } diff --git a/common/rdr/FdOutStream.cxx b/common/rdr/FdOutStream.cxx index 1757dc35..f5d07e4b 100644 --- a/common/rdr/FdOutStream.cxx +++ b/common/rdr/FdOutStream.cxx @@ -149,9 +149,10 @@ size_t FdOutStream::overrun(size_t itemSize, size_t nItems) } } - // Can we fit all the items asked for? - if (itemSize * nItems > (size_t)(end - ptr)) - nItems = (end - ptr) / itemSize; + size_t nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; return nItems; } diff --git a/common/rdr/FileInStream.cxx b/common/rdr/FileInStream.cxx index 94f5db88..bdb05a3a 100644 --- a/common/rdr/FileInStream.cxx +++ b/common/rdr/FileInStream.cxx @@ -68,7 +68,7 @@ size_t FileInStream::overrun(size_t itemSize, size_t nItems, bool wait) ptr = b; - while (end < b + itemSize) { + while ((size_t)(end - b) < itemSize) { size_t n = fread((U8 *)end, b + sizeof(b) - end, 1, file); if (n == 0) { if (ferror(file)) @@ -80,8 +80,10 @@ size_t FileInStream::overrun(size_t itemSize, size_t nItems, bool wait) end += b + sizeof(b) - end; } - if (itemSize * nItems > (size_t)(end - ptr)) - nItems = (end - ptr) / itemSize; + size_t nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; return nItems; } diff --git a/common/rdr/HexInStream.cxx b/common/rdr/HexInStream.cxx index 8f939889..a6bc92cd 100644 --- a/common/rdr/HexInStream.cxx +++ b/common/rdr/HexInStream.cxx @@ -91,7 +91,7 @@ size_t HexInStream::overrun(size_t itemSize, size_t nItems, bool wait) { offset += ptr - start; ptr = start; - while (end < ptr + itemSize) { + while ((size_t)(end - ptr) < itemSize) { size_t n = in_stream.check(2, 1, wait); if (n == 0) return 0; const U8* iptr = in_stream.getptr(); @@ -110,8 +110,10 @@ size_t HexInStream::overrun(size_t itemSize, size_t nItems, bool wait) { end += length; } - if (itemSize * nItems > (size_t)(end - ptr)) - nItems = (end - ptr) / itemSize; + size_t nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; return nItems; } diff --git a/common/rdr/HexOutStream.cxx b/common/rdr/HexOutStream.cxx index 7232514c..eac2eff8 100644 --- a/common/rdr/HexOutStream.cxx +++ b/common/rdr/HexOutStream.cxx @@ -102,8 +102,10 @@ HexOutStream::overrun(size_t itemSize, size_t nItems) { writeBuffer(); - if (itemSize * nItems > (size_t)(end - ptr)) - nItems = (end - ptr) / itemSize; + size_t nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; return nItems; } diff --git a/common/rdr/InStream.h b/common/rdr/InStream.h index 14ecf093..f71a4d9e 100644 --- a/common/rdr/InStream.h +++ b/common/rdr/InStream.h @@ -43,12 +43,15 @@ namespace rdr { inline size_t check(size_t itemSize, size_t nItems=1, bool wait=true) { - if (ptr + itemSize * nItems > end) { - if (ptr + itemSize > end) - return overrun(itemSize, nItems, wait); + size_t nAvail; + + if (itemSize > (size_t)(end - ptr)) + return overrun(itemSize, nItems, wait); + + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; - nItems = (end - ptr) / itemSize; - } return nItems; } @@ -93,13 +96,12 @@ namespace rdr { // readBytes() reads an exact number of bytes. void readBytes(void* data, size_t length) { - U8* dataPtr = (U8*)data; - U8* dataEnd = dataPtr + length; - while (dataPtr < dataEnd) { - size_t n = check(1, dataEnd - dataPtr); - memcpy(dataPtr, ptr, n); + while (length > 0) { + size_t n = check(1, length); + memcpy(data, ptr, n); ptr += n; - dataPtr += n; + data = (U8*)data + n; + length -= n; } } diff --git a/common/rdr/MemOutStream.h b/common/rdr/MemOutStream.h index 4a815b30..b56bac3a 100644 --- a/common/rdr/MemOutStream.h +++ b/common/rdr/MemOutStream.h @@ -23,6 +23,7 @@ #ifndef __RDR_MEMOUTSTREAM_H__ #define __RDR_MEMOUTSTREAM_H__ +#include <rdr/Exception.h> #include <rdr/OutStream.h> namespace rdr { @@ -65,6 +66,9 @@ namespace rdr { if (len < (size_t)(end - start) * 2) len = (end - start) * 2; + if (len < (size_t)(end - start)) + throw Exception("Overflow in MemOutStream::overrun()"); + U8* newStart = new U8[len]; memcpy(newStart, start, ptr - start); ptr = newStart + (ptr - start); diff --git a/common/rdr/OutStream.h b/common/rdr/OutStream.h index 11aafd2d..0f60ccc1 100644 --- a/common/rdr/OutStream.h +++ b/common/rdr/OutStream.h @@ -46,12 +46,15 @@ namespace rdr { inline size_t check(size_t itemSize, size_t nItems=1) { - if (ptr + itemSize * nItems > end) { - if (ptr + itemSize > end) - return overrun(itemSize, nItems); + size_t nAvail; + + if (itemSize > (size_t)(end - ptr)) + return overrun(itemSize, nItems); + + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; - nItems = (end - ptr) / itemSize; - } return nItems; } @@ -91,13 +94,12 @@ namespace rdr { // writeBytes() writes an exact number of bytes. void writeBytes(const void* data, size_t length) { - const U8* dataPtr = (const U8*)data; - const U8* dataEnd = dataPtr + length; - while (dataPtr < dataEnd) { - size_t n = check(1, dataEnd - dataPtr); - memcpy(ptr, dataPtr, n); + while (length > 0) { + size_t n = check(1, length); + memcpy(ptr, data, n); ptr += n; - dataPtr += n; + data = (U8*)data + n; + length -= n; } } diff --git a/common/rdr/RandomStream.cxx b/common/rdr/RandomStream.cxx index d5f1cc85..1be9b251 100644 --- a/common/rdr/RandomStream.cxx +++ b/common/rdr/RandomStream.cxx @@ -126,8 +126,10 @@ size_t RandomStream::overrun(size_t itemSize, size_t nItems, bool wait) { *(U8*)end++ = (int) (256.0*rand()/(RAND_MAX+1.0)); } - if (itemSize * nItems > (size_t)(end - ptr)) - nItems = (end - ptr) / itemSize; + size_t nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; return nItems; } diff --git a/common/rdr/TLSInStream.cxx b/common/rdr/TLSInStream.cxx index d0f94263..3e1172f1 100644 --- a/common/rdr/TLSInStream.cxx +++ b/common/rdr/TLSInStream.cxx @@ -43,7 +43,7 @@ ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size) return -1; } - if (in->getend() - in->getptr() < (ptrdiff_t)size) + if ((size_t)(in->getend() - in->getptr()) < size) size = in->getend() - in->getptr(); in->readBytes(data, size); @@ -92,15 +92,17 @@ size_t TLSInStream::overrun(size_t itemSize, size_t nItems, bool wait) end -= ptr - start; ptr = start; - while (end < start + itemSize) { + while ((size_t)(end - start) < itemSize) { size_t n = readTLS((U8*) end, start + bufSize - end, wait); if (!wait && n == 0) return 0; end += n; } - if (itemSize * nItems > (size_t)(end - ptr)) - nItems = (end - ptr) / itemSize; + size_t nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; return nItems; } diff --git a/common/rdr/TLSOutStream.cxx b/common/rdr/TLSOutStream.cxx index 30c456fe..7d7c3b56 100644 --- a/common/rdr/TLSOutStream.cxx +++ b/common/rdr/TLSOutStream.cxx @@ -100,8 +100,10 @@ size_t TLSOutStream::overrun(size_t itemSize, size_t nItems) flush(); - if (itemSize * nItems > (size_t)(end - ptr)) - nItems = (end - ptr) / itemSize; + size_t nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; return nItems; } diff --git a/common/rdr/ZlibInStream.cxx b/common/rdr/ZlibInStream.cxx index e2f971c7..9fcfaf6b 100644 --- a/common/rdr/ZlibInStream.cxx +++ b/common/rdr/ZlibInStream.cxx @@ -113,8 +113,10 @@ size_t ZlibInStream::overrun(size_t itemSize, size_t nItems, bool wait) return 0; } - if (itemSize * nItems > (size_t)(end - ptr)) - nItems = (end - ptr) / itemSize; + size_t nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; return nItems; } diff --git a/common/rdr/ZlibOutStream.cxx b/common/rdr/ZlibOutStream.cxx index 26a11315..7a0d692c 100644 --- a/common/rdr/ZlibOutStream.cxx +++ b/common/rdr/ZlibOutStream.cxx @@ -130,8 +130,10 @@ size_t ZlibOutStream::overrun(size_t itemSize, size_t nItems) } } - if (itemSize * nItems > (size_t)(end - ptr)) - nItems = (end - ptr) / itemSize; + size_t nAvail; + nAvail = (end - ptr) / itemSize; + if (nAvail < nItems) + return nAvail; return nItems; } -- 2.16.4 ++++++ 0012-Add-unit-tests-for-PixelFormat.is888-detection.patch ++++++ >From 91bdaa6c87a7f311163b5f1e4bbcd9de584968cd Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Wed, 2 Oct 2019 16:05:34 +0200 Subject: [PATCH] Add unit tests for PixelFormat.is888() detection --- tests/unit/pixelformat.cxx | 60 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/tests/unit/pixelformat.cxx b/tests/unit/pixelformat.cxx index 46fecfb4..cfae2f9d 100644 --- a/tests/unit/pixelformat.cxx +++ b/tests/unit/pixelformat.cxx @@ -52,8 +52,31 @@ static void doTest(bool should_fail, int b, int d, bool e, bool t, fflush(stdout); } -int main(int argc, char** argv) +static void do888Test(bool expected, int b, int d, bool e, bool t, + int rm, int gm, int bm, int rs, int gs, int bs) +{ + rfb::PixelFormat* pf; + + printf("PixelFormat(%d, %d, %s, %s, %d, %d, %d, %d, %d, %d): ", + b, d, e ? "true" : "false", t ? "true": "false", + rm, gm, bm, rs, gs, bs); + + pf = new rfb::PixelFormat(b, d, e, t, rm, gm, bm, rs, gs, bs); + + if (pf->is888() == expected) + printf("OK"); + else + printf("FAILED"); + printf("\n"); + fflush(stdout); + + delete pf; +} + +static void sanityTests() { + printf("Sanity checks:\n\n"); + /* Normal true color formats */ doTest(false, 32, 24, false, true, 255, 255, 255, 0, 8, 16); @@ -120,5 +143,40 @@ int main(int argc, char** argv) doTest(true, 32, 24, false, true, 255, 255, 255, 0, 8, 15); doTest(true, 32, 24, false, true, 255, 255, 255, 0, 16, 7); + printf("\n"); +} + +void is888Tests() +{ + printf("Simple format detection:\n\n"); + + /* Positive cases */ + + do888Test(true, 32, 24, false, true, 255, 255, 255, 0, 8, 16); + do888Test(true, 32, 24, false, true, 255, 255, 255, 24, 16, 8); + do888Test(true, 32, 24, false, true, 255, 255, 255, 24, 8, 0); + + /* Low depth */ + + do888Test(false, 32, 16, false, true, 15, 31, 15, 0, 8, 16); + do888Test(false, 32, 8, false, true, 3, 7, 3, 0, 8, 16); + + /* Low bpp and depth */ + + do888Test(false, 16, 16, false, true, 15, 31, 15, 0, 5, 11); + do888Test(false, 8, 8, false, true, 3, 7, 3, 0, 2, 5); + + /* Colour map */ + + do888Test(false, 8, 8, false, false, 0, 0, 0, 0, 0, 0); + + printf("\n"); +} + +int main(int argc, char** argv) +{ + sanityTests(); + is888Tests(); + return 0; } -- 2.16.4 ++++++ 0013-Handle-pixel-formats-with-odd-shift-values.patch ++++++ >From 05e28490873a861379c943bf616614b78b558b89 Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Wed, 2 Oct 2019 16:06:08 +0200 Subject: [PATCH] Handle pixel formats with odd shift values Our fast paths assume that each channel fits in to a separate byte. That means the shift needs to be a multiple of 8. Start actually checking this so that a client cannot trip us up and possibly cause incorrect code exection. Issue found by Pavel Cheremushkin from Kaspersky Lab. --- common/rfb/PixelFormat.cxx | 6 ++++++ tests/unit/pixelformat.cxx | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx index 789c43ed..1b4ab1ba 100644 --- a/common/rfb/PixelFormat.cxx +++ b/common/rfb/PixelFormat.cxx @@ -206,6 +206,12 @@ bool PixelFormat::is888(void) const return false; if (blueMax != 255) return false; + if ((redShift & 0x7) != 0) + return false; + if ((greenShift & 0x7) != 0) + return false; + if ((blueShift & 0x7) != 0) + return false; return true; } diff --git a/tests/unit/pixelformat.cxx b/tests/unit/pixelformat.cxx index cfae2f9d..2e0c0bbb 100644 --- a/tests/unit/pixelformat.cxx +++ b/tests/unit/pixelformat.cxx @@ -170,6 +170,12 @@ void is888Tests() do888Test(false, 8, 8, false, false, 0, 0, 0, 0, 0, 0); + /* Odd shifts */ + + do888Test(false, 32, 24, false, true, 255, 255, 255, 0, 8, 18); + do888Test(false, 32, 24, false, true, 255, 255, 255, 0, 11, 24); + do888Test(false, 32, 24, false, true, 255, 255, 255, 4, 16, 24); + printf("\n"); } -- 2.16.4 ++++++ 10-libvnc.conf ++++++ # This file contains configuration of libvnc.so module # # To get libvnc.so module working, do this: # 1. run "vncpasswd" as root user # 2. uncomment configuration lines below # # Please note you can specify any option which Xvnc accepts. # Refer to `Xvnc -help` output for detailed list of options. #Section "Module" # Load "vnc" #EndSection #Section "Screen" # Identifier "Screen0" # Option "SecurityTypes" "VncAuth" # Option "PasswordFile" "/root/.vnc/passwd" #EndSection ++++++ U_0001-Properly-store-certificate-exceptions.patch ++++++ >From b30f10c681ec87720cff85d490f67098568a9cba Mon Sep 17 00:00:00 2001 From: Pierre Ossman <oss...@cendio.se> Date: Thu, 21 May 2020 21:10:38 +0200 Subject: [PATCH] Properly store certificate exceptions The previous method stored the certificates as authorities, meaning that the owner of that certificate could impersonate any server it wanted after a client had added an exception. Handle this more properly by only storing exceptions for specific hostname/certificate combinations, the same way browsers or SSH does things. --- common/rfb/CSecurityTLS.cxx | 163 ++++++++++++++++++++------------------------ 1 file changed, 73 insertions(+), 90 deletions(-) Index: tigervnc-1.9.0/common/rfb/CSecurityTLS.cxx =================================================================== --- tigervnc-1.9.0.orig/common/rfb/CSecurityTLS.cxx +++ tigervnc-1.9.0/common/rfb/CSecurityTLS.cxx @@ -232,22 +232,6 @@ void CSecurityTLS::setParam() if (*cafile && gnutls_certificate_set_x509_trust_file(cert_cred,cafile,GNUTLS_X509_FMT_PEM) < 0) throw AuthFailureException("load of CA cert failed"); - /* Load previously saved certs */ - char *homeDir = NULL; - int err; - if (getvnchomedir(&homeDir) == -1) - vlog.error("Could not obtain VNC home directory path"); - else { - CharArray caSave(strlen(homeDir) + 19 + 1); - sprintf(caSave.buf, "%sx509_savedcerts.pem", homeDir); - delete [] homeDir; - - err = gnutls_certificate_set_x509_trust_file(cert_cred, caSave.buf, - GNUTLS_X509_FMT_PEM); - if (err < 0) - vlog.debug("Failed to load saved server certificates from %s", caSave.buf); - } - if (*crlfile && gnutls_certificate_set_x509_crl_file(cert_cred,crlfile,GNUTLS_X509_FMT_PEM) < 0) throw AuthFailureException("load of CRL failed"); @@ -272,7 +256,10 @@ void CSecurityTLS::checkSession() const gnutls_datum_t *cert_list; unsigned int cert_list_size = 0; int err; + + char *homeDir; gnutls_datum_t info; + size_t len; if (anon) return; @@ -315,13 +302,13 @@ void CSecurityTLS::checkSession() throw AuthFailureException("decoding of certificate failed"); if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) { - char buf[255]; + CharArray text; vlog.debug("hostname mismatch"); - snprintf(buf, sizeof(buf), "Hostname (%s) does not match any certificate, " - "do you want to continue?", client->getServerName()); - buf[sizeof(buf) - 1] = '\0'; - if (!msg->showMsgBox(UserMsgBox::M_YESNO, "hostname mismatch", buf)) - throw AuthFailureException("hostname mismatch"); + text.format("Hostname (%s) does not match the server certificate, " + "do you want to continue?", client->getServerName()); + if (!msg->showMsgBox(UserMsgBox::M_YESNO, + "Certificate hostname mismatch", text.buf)) + throw AuthFailureException("Certificate hostname mismatch"); } if (status == 0) { @@ -346,89 +333,81 @@ void CSecurityTLS::checkSession() throw AuthFailureException("Invalid status of server certificate verification"); } - vlog.debug("Saved server certificates don't match"); - - if (gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info)) { - /* - * GNUTLS doesn't correctly export gnutls_free symbol which is - * a function pointer. Linking with Visual Studio 2008 Express will - * fail when you call gnutls_free(). - */ -#if WIN32 - free(info.data); -#else - gnutls_free(info.data); -#endif - throw AuthFailureException("Could not find certificate to display"); + /* Certificate is fine, except we don't know the issuer, so TOFU time */ + homeDir = NULL; + if (getvnchomedir(&homeDir) == -1) { + throw AuthFailureException("Could not obtain VNC home directory " + "path for known hosts storage"); + } + + CharArray dbPath(strlen(homeDir) + 16 + 1); + sprintf(dbPath.buf, "%sx509_known_hosts", homeDir); + delete [] homeDir; + + err = gnutls_verify_stored_pubkey(dbPath.buf, NULL, + client->getServerName(), NULL, + GNUTLS_CRT_X509, &cert_list[0], 0); + + /* Previously known? */ + if (err == GNUTLS_E_SUCCESS) { + vlog.debug("Server certificate found in known hosts file"); + gnutls_x509_crt_deinit(crt); + return; } - size_t out_size = 0; - char *out_buf = NULL; - char *certinfo = NULL; - int len = 0; - - vlog.debug("certificate issuer unknown"); - - len = snprintf(NULL, 0, "This certificate has been signed by an unknown " - "authority:\n\n%s\n\nDo you want to save it and " - "continue?\n ", info.data); - if (len < 0) - AuthFailureException("certificate decoding error"); - - vlog.debug("%s", info.data); - - certinfo = new char[len]; - if (certinfo == NULL) - throw AuthFailureException("Out of memory"); - - snprintf(certinfo, len, "This certificate has been signed by an unknown " - "authority:\n\n%s\n\nDo you want to save it and " - "continue? ", info.data); - - for (int i = 0; i < len - 1; i++) - if (certinfo[i] == ',' && certinfo[i + 1] == ' ') - certinfo[i] = '\n'; - - if (!msg->showMsgBox(UserMsgBox::M_YESNO, "certificate issuer unknown", - certinfo)) { - delete [] certinfo; - throw AuthFailureException("certificate issuer unknown"); - } - - delete [] certinfo; - - if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, NULL, &out_size) - == GNUTLS_E_SHORT_MEMORY_BUFFER) - AuthFailureException("Out of memory"); - - // Save cert - out_buf = new char[out_size]; - if (out_buf == NULL) - AuthFailureException("Out of memory"); - - if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, out_buf, &out_size) < 0) - AuthFailureException("certificate issuer unknown, and certificate " - "export failed"); - - char *homeDir = NULL; - if (getvnchomedir(&homeDir) == -1) - vlog.error("Could not obtain VNC home directory path"); - else { - FILE *f; - CharArray caSave(strlen(homeDir) + 1 + 19); - sprintf(caSave.buf, "%sx509_savedcerts.pem", homeDir); - delete [] homeDir; - f = fopen(caSave.buf, "a+"); - if (!f) - msg->showMsgBox(UserMsgBox::M_OK, "certificate save failed", - "Could not save the certificate"); - else { - fprintf(f, "%s\n", out_buf); - fclose(f); - } + if ((err != GNUTLS_E_NO_CERTIFICATE_FOUND) && + (err != GNUTLS_E_CERTIFICATE_KEY_MISMATCH)) { + throw AuthFailureException("Could not load known hosts database"); } - delete [] out_buf; + if (gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info)) + throw AuthFailureException("Could not find certificate to display"); + + len = strlen((char*)info.data); + for (size_t i = 0; i < len - 1; i++) { + if (info.data[i] == ',' && info.data[i + 1] == ' ') + info.data[i] = '\n'; + } + + /* New host */ + if (err == GNUTLS_E_NO_CERTIFICATE_FOUND) { + CharArray text; + + vlog.debug("Server host not previously known"); + vlog.debug("%s", info.data); + + text.format("This certificate has been signed by an unknown " + "authority:\n\n%s\n\nSomeone could be trying to " + "impersonate the site and you should not " + "continue.\n\nDo you want to make an exception " + "for this server?", info.data); + + if (!msg->showMsgBox(UserMsgBox::M_YESNO, + "Unknown certificate issuer", + text.buf)) + throw AuthFailureException("Unknown certificate issuer"); + } else if (err == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { + CharArray text; + + vlog.debug("Server host key mismatch"); + vlog.debug("%s", info.data); + + text.format("This host is previously known with a different " + "certificate, and the new certificate has been " + "signed by an unknown authority:\n\n%s\n\nSomeone " + "could be trying to impersonate the site and you " + "should not continue.\n\nDo you want to make an " + "exception for this server?", info.data); + + if (!msg->showMsgBox(UserMsgBox::M_YESNO, + "Unexpected server certificate", + text.buf)) + throw AuthFailureException("Unexpected server certificate"); + } + + if (gnutls_store_pubkey(dbPath.buf, NULL, client->getServerName(), + NULL, GNUTLS_CRT_X509, &cert_list[0], 0, 0)) + vlog.error("Failed to store server certificate to known hosts database"); gnutls_x509_crt_deinit(crt); /* ++++++ U_0002-Properly-store-certificate-exceptions-in-Java-viewer.patch ++++++ >From f029745f63ac7d22fb91639b2cb5b3ab56134d6e Mon Sep 17 00:00:00 2001 From: "Brian P. Hinz" <bph...@users.sf.net> Date: Tue, 8 Sep 2020 10:13:32 +0200 Subject: [PATCH] Properly store certificate exceptions in Java viewer Like the native viewer, the Java viewer didn't store certificate exceptions properly. Whilst not as bad as the native viewer, it still failed to check that a stored certificate wouldn't be maliciously used for another server. In practice this can in most cases be used to impersonate another server. Handle this like the native viewer by storing exceptions for a specific hostname/certificate combination. --- java/com/tigervnc/rfb/CSecurityTLS.java | 164 ++++++++++++++++++++------------ 1 file changed, 101 insertions(+), 63 deletions(-) Index: tigervnc-1.9.0/java/com/tigervnc/rfb/CSecurityTLS.java =================================================================== --- tigervnc-1.9.0.orig/java/com/tigervnc/rfb/CSecurityTLS.java +++ tigervnc-1.9.0/java/com/tigervnc/rfb/CSecurityTLS.java @@ -41,6 +41,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -107,12 +108,6 @@ public class CSecurityTLS extends CSecur X509CRL.setDefaultStr(getDefaultCRL()); } -// FIXME: -// Need to shutdown the connection cleanly - -// FIXME? -// add a finalizer method that calls shutdown - public boolean processMsg(CConnection cc) { is = (FdInStream)cc.getInStream(); os = (FdOutStream)cc.getOutStream(); @@ -257,8 +252,13 @@ public class CSecurityTLS extends CSecur { Collection<? extends Certificate> certs = null; X509Certificate cert = chain[0]; + String pk = + Base64.getEncoder().encodeToString(cert.getPublicKey().getEncoded()); try { cert.checkValidity(); + verifyHostname(cert); + } catch(CertificateParsingException e) { + throw new SystemException(e.getMessage()); } catch(CertificateNotYetValidException e) { throw new AuthFailureException("server certificate has not been activated"); } catch(CertificateExpiredException e) { @@ -267,73 +267,111 @@ public class CSecurityTLS extends CSecur "do you want to continue?")) throw new AuthFailureException("server certificate has expired"); } - String thumbprint = getThumbprint(cert); File vncDir = new File(FileUtils.getVncHomeDir()); - File certFile = new File(vncDir, "x509_savedcerts.pem"); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - if (vncDir.exists() && certFile.exists() && certFile.canRead()) { - InputStream certStream = new MyFileInputStream(certFile); - certs = cf.generateCertificates(certStream); - for (Certificate c : certs) - if (thumbprint.equals(getThumbprint((X509Certificate)c))) - return; - } + if (!vncDir.exists()) + throw new AuthFailureException("Could not obtain VNC home directory "+ + "path for known hosts storage"); + File dbPath = new File(vncDir, "x509_known_hosts"); + String info = + " Subject: "+cert.getSubjectX500Principal().getName()+"\n"+ + " Issuer: "+cert.getIssuerX500Principal().getName()+"\n"+ + " Serial Number: "+cert.getSerialNumber()+"\n"+ + " Version: "+cert.getVersion()+"\n"+ + " Signature Algorithm: "+cert.getPublicKey().getAlgorithm()+"\n"+ + " Not Valid Before: "+cert.getNotBefore()+"\n"+ + " Not Valid After: "+cert.getNotAfter()+"\n"+ + " SHA-1 Fingerprint: "+getThumbprint(cert)+"\n"; try { - verifyHostname(cert); - tm.checkServerTrusted(chain, authType); - } catch (java.lang.Exception e) { - if (e.getCause() instanceof CertPathBuilderException) { - String certinfo = - "This certificate has been signed by an unknown authority\n"+ - "\n"+ - " Subject: "+cert.getSubjectX500Principal().getName()+"\n"+ - " Issuer: "+cert.getIssuerX500Principal().getName()+"\n"+ - " Serial Number: "+cert.getSerialNumber()+"\n"+ - " Version: "+cert.getVersion()+"\n"+ - " Signature Algorithm: "+cert.getPublicKey().getAlgorithm()+"\n"+ - " Not Valid Before: "+cert.getNotBefore()+"\n"+ - " Not Valid After: "+cert.getNotAfter()+"\n"+ - " SHA1 Fingerprint: "+getThumbprint(cert)+"\n"+ - "\n"+ - "Do you want to save it and continue?"; - if (!msg.showMsgBox(YES_NO_OPTION, "certificate issuer unknown", - certinfo)) { - throw new AuthFailureException("certificate issuer unknown"); - } - if (certs == null || !certs.contains(cert)) { - byte[] der = cert.getEncoded(); - String pem = DatatypeConverter.printBase64Binary(der); - pem = pem.replaceAll("(.{64})", "$1\n"); - FileWriter fw = null; - try { - if (!vncDir.exists()) - vncDir.mkdir(); - if (!certFile.exists() && !certFile.createNewFile()) { - vlog.error("Certificate save failed."); - } else { - fw = new FileWriter(certFile.getAbsolutePath(), true); - fw.write("-----BEGIN CERTIFICATE-----\n"); - fw.write(pem+"\n"); - fw.write("-----END CERTIFICATE-----\n"); - } - } catch (IOException ioe) { - msg.showMsgBox(OK_OPTION, "certificate save failed", - "Could not save the certificate"); - } finally { - try { - if (fw != null) - fw.close(); - } catch(IOException ioe2) { - throw new Exception(ioe2.getMessage()); + if (dbPath.exists()) { + FileReader db = new FileReader(dbPath); + BufferedReader dbBuf = new BufferedReader(db); + String line; + String server = client.getServerName().toLowerCase(); + while ((line = dbBuf.readLine())!=null) { + String fields[] = line.split("\\|"); + if (fields.length==6) { + if (server.equals(fields[2]) && pk.equals(fields[5])) { + vlog.debug("Server certificate found in known hosts file"); + dbBuf.close(); + return; + } else if (server.equals(fields[2]) && !pk.equals(fields[5]) || + !server.equals(fields[2]) && pk.equals(fields[5])) { + throw new CertStoreException(); } } } + dbBuf.close(); + } + tm.checkServerTrusted(chain, authType); + } catch (IOException e) { + throw new AuthFailureException("Could not load known hosts database"); + } catch (CertStoreException e) { + vlog.debug("Server host key mismatch"); + vlog.debug(info); + String text = + "This host is previously known with a different "+ + "certificate, and the new certificate has been "+ + "signed by an unknown authority\n"+ + "\n"+info+"\n"+ + "Someone could be trying to impersonate the site and you should not continue.\n"+ + "\n"+ + "Do you want to make an exception for this server?"; + if (!msg.showMsgBox(YES_NO_OPTION, "Unexpected certificate issuer", text)) + throw new AuthFailureException("Unexpected certificate issuer"); + store_pubkey(dbPath, client.getServerName().toLowerCase(), pk); + } catch (java.lang.Exception e) { + if (e.getCause() instanceof CertPathBuilderException) { + vlog.debug("Server host not previously known"); + vlog.debug(info); + String text = + "This certificate has been signed by an unknown authority\n"+ + "\n"+info+"\n"+ + "Someone could be trying to impersonate the site and you should not continue.\n"+ + "\n"+ + "Do you want to make an exception for this server?"; + if (!msg.showMsgBox(YES_NO_OPTION, "Unknown certificate issuer", text)) + throw new AuthFailureException("Unknown certificate issuer"); + store_pubkey(dbPath, client.getServerName().toLowerCase(), pk); } else { throw new SystemException(e.getMessage()); } } } + private void store_pubkey(File dbPath, String serverName, String pk) + { + ArrayList<String> lines = new ArrayList<String>(); + File vncDir = new File(FileUtils.getVncHomeDir()); + try { + if (dbPath.exists()) { + FileReader db = new FileReader(dbPath); + BufferedReader dbBuf = new BufferedReader(db); + String line; + while ((line = dbBuf.readLine())!=null) { + String fields[] = line.split("\\|"); + if (fields.length==6) + if (!serverName.equals(fields[2]) && !pk.equals(fields[5])) + lines.add(line); + } + dbBuf.close(); + } + } catch (IOException e) { + throw new AuthFailureException("Could not load known hosts database"); + } + try { + if (!dbPath.exists()) + dbPath.createNewFile(); + FileWriter fw = new FileWriter(dbPath.getAbsolutePath(), false); + Iterator i = lines.iterator(); + while (i.hasNext()) + fw.write((String)i.next()+"\n"); + fw.write("|g0|"+serverName+"|*|0|"+pk+"\n"); + fw.close(); + } catch (IOException e) { + vlog.error("Failed to store server certificate to known hosts database"); + } + } + public X509Certificate[] getAcceptedIssuers () { return tm.getAcceptedIssuers(); @@ -389,12 +427,13 @@ public class CSecurityTLS extends CSecur } Object[] answer = {"YES", "NO"}; int ret = JOptionPane.showOptionDialog(null, - "Hostname verification failed. Do you want to continue?", - "Hostname Verification Failure", + "Hostname ("+client.getServerName()+") does not match the"+ + " server certificate, do you want to continue?", + "Certificate hostname mismatch", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, answer, answer[0]); if (ret != JOptionPane.YES_OPTION) - throw new WarningException("Hostname verification failed."); + throw new WarningException("Certificate hostname mismatch."); } catch (CertificateParsingException e) { throw new SystemException(e.getMessage()); } catch (InvalidNameException e) { ++++++ U_Avoid-potential-crash-when-replacing-buffer-in-Plain.patch ++++++ >From a752d8fd7a0622e11dda72f690d4fea8cb913178 Mon Sep 17 00:00:00 2001 From: Jan Grulich <jgrul...@redhat.com> Date: Mon, 1 Oct 2018 10:17:20 +0200 Subject: [PATCH 1/5] Avoid potential crash when replacing buffer in PlainPasswd --- common/rfb/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/rfb/util.h b/common/rfb/util.h index b678b890..9e59bd37 100644 --- a/common/rfb/util.h +++ b/common/rfb/util.h @@ -50,7 +50,7 @@ namespace rfb { CharArray() : buf(0) {} CharArray(char* str) : buf(str) {} // note: assumes ownership CharArray(size_t len) { - buf = new char[len]; + buf = new char[len](); } ~CharArray() { delete [] buf; -- 2.16.4 ++++++ U_viewer-reset-ctrl-alt-to-menu-state-on-focus.patch ++++++ >From 9f83180219380c690fb743182308bc2d534b8b1b Mon Sep 17 00:00:00 2001 From: Dominique Martinet <asmad...@codewreck.org> Date: Sun, 8 Jul 2018 02:15:43 +0900 Subject: [PATCH] viewer: reset ctrl / alt to menu state on focus Setting Ctrl or Alt key on menu only sends the key press, and the state is lost when focus is lost and recovered. This checks the menu variable and sends the keys again if needed. --- vncviewer/Viewport.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 4e23dc8c..317f06b2 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -635,6 +635,12 @@ int Viewport::handle(int event) exit_vncviewer(e.str()); } + // Resend Ctrl/Alt if needed + if (menuCtrlKey) + handleKeyPress(0x1d, XK_Control_L); + if (menuAltKey) + handleKeyPress(0x38, XK_Alt_L); + // Yes, we would like some focus please! return 1; -- 2.16.4 ++++++ index.vnc ++++++ <!-- index.vnc - default HTML page for TigerVNC Java viewer applet, to be used with Xvnc. On any file ending in .vnc, the HTTP server embedded in Xvnc will substitute the following variables when preceded by a dollar: USER, DESKTOP, DISPLAY, APPLETWIDTH, APPLETHEIGHT, WIDTH, HEIGHT, PORT, Use two dollar signs ($$) to get a dollar sign in the generated HTML page. --> <HTML> <TITLE> $USER's $DESKTOP desktop ($DISPLAY) </TITLE> <APPLET CODE="com.tigervnc.vncviewer.VncViewer" ARCHIVE="VncViewer.jar" WIDTH="$APPLETWIDTH" HEIGHT="$APPLETHEIGHT"> <PARAM NAME="Port" VALUE="$PORT"> <PARAM NAME="Embed" VALUE="true"> <PARAM NAME="AlwaysShowServerDialog" VALUE="false"> </APPLET> <BR> <A href="http://www.tigervnc.org/">TigerVNC site</A> </HTML> ++++++ n_correct_path_in_desktop_file.patch ++++++ Our /usr/bin/vncviewer is symlink to alternatives. This desktop file is named specifically "TigerVNC Viewer", so lets start /usr/bin/vncviewer-tigervnc, no matter what the currently selected alternative is. Index: tigervnc-1.9.0/vncviewer/vncviewer.desktop.in.in =================================================================== --- tigervnc-1.9.0.orig/vncviewer/vncviewer.desktop.in.in +++ tigervnc-1.9.0/vncviewer/vncviewer.desktop.in.in @@ -2,7 +2,7 @@ Name=TigerVNC Viewer GenericName=Remote Desktop Viewer Comment=Connect to VNC server and display remote desktop -Exec=@BIN_DIR@/vncviewer +Exec=@BIN_DIR@/vncviewer-tigervnc Icon=tigervnc Terminal=false Type=Application ++++++ n_tigervnc-date-time.patch ++++++ Index: tigervnc-1.9.0/unix/xserver/hw/vnc/buildtime.c =================================================================== --- tigervnc-1.9.0.orig/unix/xserver/hw/vnc/buildtime.c +++ tigervnc-1.9.0/unix/xserver/hw/vnc/buildtime.c @@ -15,4 +15,4 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ -char buildtime[] = __DATE__ " " __TIME__; +char buildtime[] = "??? ?? ???? ??:??:??"; Index: tigervnc-1.9.0/unix/vncconfig/buildtime.c =================================================================== --- tigervnc-1.9.0.orig/unix/vncconfig/buildtime.c +++ tigervnc-1.9.0/unix/vncconfig/buildtime.c @@ -15,4 +15,4 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ -char buildtime[] = __DATE__ " " __TIME__; +char buildtime[] = "??? ?? ???? ??:??:??"; Index: tigervnc-1.9.0/unix/x0vncserver/buildtime.c =================================================================== --- tigervnc-1.9.0.orig/unix/x0vncserver/buildtime.c +++ tigervnc-1.9.0/unix/x0vncserver/buildtime.c @@ -15,4 +15,4 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ -char buildtime[] = __DATE__ " " __TIME__; +char buildtime[] = "??? ?? ???? ??:??:??"; Index: tigervnc-1.9.0/win/winvnc/buildTime.cxx =================================================================== --- tigervnc-1.9.0.orig/win/winvnc/buildTime.cxx +++ tigervnc-1.9.0/win/winvnc/buildTime.cxx @@ -15,4 +15,4 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ -const char* buildTime = "Built on " __DATE__ " at " __TIME__; +const char* buildTime = "Built on ??? ?? ???? at ??:??:??"; Index: tigervnc-1.9.0/CMakeLists.txt =================================================================== --- tigervnc-1.9.0.orig/CMakeLists.txt +++ tigervnc-1.9.0/CMakeLists.txt @@ -42,12 +42,6 @@ if(MSVC) message(FATAL_ERROR "TigerVNC cannot be built with Visual Studio. Please use MinGW") endif() -if(NOT BUILD_TIMESTAMP) - set(BUILD_TIMESTAMP "") - execute_process(COMMAND "date" "+%Y-%m-%d %H:%M" OUTPUT_VARIABLE BUILD_TIMESTAMP) - string(REGEX REPLACE "\n" "" BUILD_TIMESTAMP ${BUILD_TIMESTAMP}) -endif() - # Default to optimised builds instead of debug ones. Our code has no bugs ;) # (CMake makes it fairly easy to toggle this back to Debug if needed) if(NOT CMAKE_BUILD_TYPE) Index: tigervnc-1.9.0/vncviewer/vncviewer.cxx =================================================================== --- tigervnc-1.9.0.orig/vncviewer/vncviewer.cxx +++ tigervnc-1.9.0/vncviewer/vncviewer.cxx @@ -98,11 +98,9 @@ static const char *about_text() // time. snprintf(buffer, sizeof(buffer), _("TigerVNC Viewer %d-bit v%s\n" - "Built on: %s\n" "Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n" "See http://www.tigervnc.org for information on TigerVNC."), - (int)sizeof(size_t)*8, PACKAGE_VERSION, - BUILD_TIMESTAMP, 2018); + (int)sizeof(size_t)*8, PACKAGE_VERSION, 2018); return buffer; } ++++++ tigervnc-clean-pressed-key-on-exit.patch ++++++ Index: tigervnc-1.9.0/vncviewer/DesktopWindow.cxx =================================================================== --- tigervnc-1.9.0.orig/vncviewer/DesktopWindow.cxx +++ tigervnc-1.9.0/vncviewer/DesktopWindow.cxx @@ -207,6 +207,8 @@ DesktopWindow::~DesktopWindow() delete statsGraph; + delete viewport; + // FLTK automatically deletes all child widgets, so we shouldn't touch // them ourselves here } Index: tigervnc-1.9.0/vncviewer/Viewport.cxx =================================================================== --- tigervnc-1.9.0.orig/vncviewer/Viewport.cxx +++ tigervnc-1.9.0/vncviewer/Viewport.cxx @@ -189,6 +189,18 @@ Viewport::Viewport(int w, int h, const r Viewport::~Viewport() { + // Send release for every pressed key + for(DownMap::iterator iter = downKeySym.begin(); iter != downKeySym.end(); ++iter) { + try { + if (iter->first > 0xff) + cc->writer()->writeKeyEvent(iter->second, 0, false); + else + cc->writer()->writeKeyEvent(iter->second, iter->first, false); + } catch (rdr::Exception& e) { + // ignore + } + } + // Unregister all timeouts in case they get a change tro trigger // again later when this object is already gone. Fl::remove_timeout(handlePointerTimeout, this); Index: tigervnc-1.9.0/vncviewer/vncviewer.cxx =================================================================== --- tigervnc-1.9.0.orig/vncviewer/vncviewer.cxx +++ tigervnc-1.9.0/vncviewer/vncviewer.cxx @@ -107,6 +107,8 @@ static const char *about_text() return buffer; } +static CConn *cc; + void exit_vncviewer(const char *error) { // Prioritise the first error we get as that is probably the most @@ -177,6 +179,16 @@ static void CleanupSignalHandler(int sig // CleanupSignalHandler allows C++ object cleanup to happen because it calls // exit() rather than the default which is to abort. vlog.info(_("Termination signal %d has been received. TigerVNC Viewer will now exit."), sig); + delete cc; + exit(1); +} + +static int CleanupXIOErrorHandler(Display *dpy) +{ + // CleanupSignalHandler allows C++ object cleanup to happen because it calls + // exit() rather than the default which is to abort. + vlog.info("XErrorHandler called"); + delete cc; exit(1); } @@ -566,6 +578,9 @@ int main(int argc, char** argv) XkbSetDetectableAutoRepeat(fl_display, True, NULL); #endif + fl_open_display(); + XSetIOErrorHandler(CleanupXIOErrorHandler); + CSecurity::upg = &dlg; #ifdef HAVE_GNUTLS CSecurityTLS::msg = &dlg; @@ -651,7 +666,7 @@ int main(int argc, char** argv) #endif } - CConn *cc = new CConn(vncServerName, sock); + cc = new CConn(vncServerName, sock); while (!exitMainloop) run_mainloop(); ++++++ tigervnc-https.firewalld ++++++ <?xml version="1.0" encoding="utf-8"?> <service> <short>VNC over HTTPS</short> <description>The xvnc-novnc servers a web-based VNC viewer over HTTPS. Allows accessing VNC using any modern browser. It displays VNC display :1.</description> <port protocol="tcp" port="5801"/> </service> ++++++ tigervnc-newfbsize.patch ++++++ Index: tigervnc-1.6.0/vncviewer/CConn.cxx =================================================================== --- tigervnc-1.6.0.orig/vncviewer/CConn.cxx +++ tigervnc-1.6.0/vncviewer/CConn.cxx @@ -438,6 +438,8 @@ void CConn::dataRect(const Rect& r, int if (encoding != encodingCopyRect) lastServerEncoding = encoding; + if (encoding == pseudoEncodingDesktopSize) + setDesktopSize( r.width(), r.height() ); CConnection::dataRect(r, encoding); ++++++ tigervnc.firewalld ++++++ <?xml version="1.0" encoding="utf-8"?> <service> <short>VNC display :1</short> <description>VNC is protocol for remote desktop. The TigerVNC service and the vncmanager service use VNC display number :1.</description> <port protocol="tcp" port="5901"/> </service> ++++++ u_build_libXvnc_as_separate_library.patch ++++++ Author: Michal Srb <michal...@gmail.com> Patch-Mainline: To be upstreamed Subject: [PATCH] Build libXvnc as separate library. So it can be used by others, not only vncconfig. diff --git a/unix/vncconfig/CMakeLists.txt b/unix/vncconfig/CMakeLists.txt index 959681f..5fe1fb8 100644 --- a/unix/vncconfig/CMakeLists.txt +++ b/unix/vncconfig/CMakeLists.txt @@ -3,13 +3,25 @@ include_directories(${X11_INCLUDE_DIR}) include_directories(${CMAKE_SOURCE_DIR}/common) include_directories(${CMAKE_SOURCE_DIR}/unix/tx) +include(GNUInstallDirs) + +add_library(Xvnc SHARED + vncExt.c) + +set_target_properties(Xvnc + PROPERTIES + VERSION 1.0.0 + SOVERSION 1 +) + add_executable(vncconfig buildtime.c - vncExt.c vncconfig.cxx QueryConnectDialog.cxx) -target_link_libraries(vncconfig tx rfb network rdr ${X11_LIBRARIES}) +target_link_libraries(vncconfig tx rfb network rdr Xvnc ${X11_LIBRARIES}) install(TARGETS vncconfig DESTINATION ${BIN_DIR}) +install(TARGETS Xvnc LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RENAME libXvnc.so) install(FILES vncconfig.man DESTINATION ${MAN_DIR}/man1 RENAME vncconfig.1) +install(FILES vncExt.h DESTINATION ${X11_INCLUDE_DIR}/X11/extensions RENAME Xvnc.h) ++++++ u_change-button-layout-in-ServerDialog.patch ++++++ Patch-mainline: To be upstreamed References: bnc#1084865 Author: Michal Srb <m...@suse.com> Subject: Change button layout in ServerDialog. To fit strings in languages with longer words... --- vncviewer/ServerDialog.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vncviewer/ServerDialog.cxx b/vncviewer/ServerDialog.cxx index de67f87b..0a8aa775 100644 --- a/vncviewer/ServerDialog.cxx +++ b/vncviewer/ServerDialog.cxx @@ -53,7 +53,7 @@ ServerDialog::ServerDialog() serverName = new Fl_Input(x, y, w() - margin*2 - server_label_width, INPUT_HEIGHT, _("VNC server:")); - int adjust = (w() - 20) / 4; + int adjust = (w() - 20) / 3; int button_width = adjust - margin/2; x = margin; @@ -76,6 +76,8 @@ ServerDialog::ServerDialog() x = 0; y += margin/2 + BUTTON_HEIGHT; + adjust = (w() - 20) / 4; + button_width = adjust - margin/2; divider = new Fl_Box(x, y, w(), 2); divider->box(FL_THIN_DOWN_FRAME); -- 2.13.6 ++++++ u_tigervnc-add-autoaccept-parameter.patch ++++++ Index: tigervnc-1.9.0/java/com/tigervnc/rfb/CSecurityTLS.java =================================================================== --- tigervnc-1.9.0.orig/java/com/tigervnc/rfb/CSecurityTLS.java +++ tigervnc-1.9.0/java/com/tigervnc/rfb/CSecurityTLS.java @@ -66,6 +66,9 @@ public class CSecurityTLS extends CSecur public static StringParameter X509CRL = new StringParameter("X509CRL", "X509 CRL file", "", Configuration.ConfigurationObject.ConfViewer); + public static StringParameter x509autoaccept + = new StringParameter("x509autoaccept", + "X509 Certificate SHA-1 fingerprint", "", Configuration.ConfigurationObject.ConfViewer); public static UserMsgBox msg; private void initGlobal() @@ -85,6 +88,7 @@ public class CSecurityTLS extends CSecur setDefaults(); cafile = X509CA.getData(); crlfile = X509CRL.getData(); + certautoaccept = x509autoaccept.getData(); } public static String getDefaultCA() { @@ -266,6 +270,7 @@ public class CSecurityTLS extends CSecur "do you want to continue?")) throw new AuthFailureException("server certificate has expired"); } + String thumbprint = getThumbprint(cert); File vncDir = new File(FileUtils.getVncHomeDir()); if (!vncDir.exists()) throw new AuthFailureException("Could not obtain VNC home directory "+ @@ -320,6 +325,9 @@ public class CSecurityTLS extends CSecur store_pubkey(dbPath, client.getServerName().toLowerCase(), pk); } catch (java.lang.Exception e) { if (e.getCause() instanceof CertPathBuilderException) { + if (certautoaccept != null && thumbprint.equalsIgnoreCase(certautoaccept)) { + return; + } vlog.debug("Server host not previously known"); vlog.debug(info); String text = @@ -509,7 +517,7 @@ public class CSecurityTLS extends CSecur private SSLEngineManager manager; private boolean anon; - private String cafile, crlfile; + private String cafile, crlfile, certautoaccept; private FdInStream is; private FdOutStream os; Index: tigervnc-1.9.0/java/com/tigervnc/vncviewer/VncViewer.java =================================================================== --- tigervnc-1.9.0.orig/java/com/tigervnc/vncviewer/VncViewer.java +++ tigervnc-1.9.0/java/com/tigervnc/vncviewer/VncViewer.java @@ -393,6 +393,8 @@ public class VncViewer extends javax.swi // Called right after zero-arg constructor in applet mode setLookAndFeel(); setBackground(Color.white); + + SecurityClient.setDefaults(); applet = this; vncServerName.put(loadAppletParameters(applet).toCharArray()).flip(); if (embed.getValue()) { ++++++ u_tigervnc-cve-2014-8240.patch ++++++ Patch-Mainline: To be upstreamed References: bnc#900896 CVE-2014-8240 Signed-off-by: Michal Srb <m...@suse.com> Index: tigervnc-1.8.0/unix/x0vncserver/Image.cxx =================================================================== --- tigervnc-1.8.0.orig/unix/x0vncserver/Image.cxx +++ tigervnc-1.8.0/unix/x0vncserver/Image.cxx @@ -80,6 +80,14 @@ void Image::Init(int width, int height) xim = XCreateImage(dpy, vis, DefaultDepth(dpy, DefaultScreen(dpy)), ZPixmap, 0, 0, width, height, BitmapPad(dpy), 0); + if (xim->bytes_per_line <= 0 || + xim->height <= 0 || + xim->height >= INT_MAX / xim->bytes_per_line) { + vlog.error("Invalid display size"); + XDestroyImage(xim); + exit(1); + } + xim->data = (char *)malloc(xim->bytes_per_line * xim->height); if (xim->data == NULL) { vlog.error("malloc() failed"); @@ -254,6 +262,17 @@ void ShmImage::Init(int width, int heigh delete shminfo; shminfo = NULL; return; + } + + if (xim->bytes_per_line <= 0 || + xim->height <= 0 || + xim->height >= INT_MAX / xim->bytes_per_line) { + vlog.error("Invalid display size"); + XDestroyImage(xim); + xim = NULL; + delete shminfo; + shminfo = NULL; + return; } shminfo->shmid = shmget(IPC_PRIVATE, ++++++ u_tigervnc-ignore-epipe-on-write.patch ++++++ Author: Michal Srb <m...@suse.com> Subject: Ignore EPIPE on write. Patch-Mainline: To be upstreamed References: bnc#864676 If the VNC server closes connection after our last read and before this write, we will report error message about EPIPE. This situation is no error, however, we should quit normally same as when we find out that connection was closed during read. Index: common/rdr/FdOutStream.cxx =================================================================== --- common/rdr/FdOutStream.cxx.orig +++ common/rdr/FdOutStream.cxx @@ -204,8 +204,12 @@ int FdOutStream::writeWithTimeout(const #endif } while (n < 0 && (errno == EINTR)); - if (n < 0) - throw SystemException("write", errno); + if (n < 0) { + if(errno == EPIPE) + n = length; // Ignore EPIPE and fake successfull write, it doesn't matter that we are writing to closed socket, we will find out once we try to read from it. + else + throw SystemException("write", errno); + } gettimeofday(&lastWrite, NULL); ++++++ u_tigervnc_update_default_vncxstartup.patch ++++++ Author: Michal Srb <m...@suse.com> References: bnc#956537 Subject: Update default vnc xstartup script. Index: tigervnc-1.6.0/unix/vncserver =================================================================== --- tigervnc-1.6.0.orig/unix/vncserver +++ tigervnc-1.6.0/unix/vncserver @@ -61,27 +61,31 @@ $defaultXStartup = ("#!/bin/sh\n\n". "unset SESSION_MANAGER\n". "unset DBUS_SESSION_BUS_ADDRESS\n". - "OS=`uname -s`\n". - "if [ \$OS = 'Linux' ]; then\n". - " case \"\$WINDOWMANAGER\" in\n". - " \*gnome\*)\n". - " if [ -e /etc/SuSE-release ]; then\n". - " PATH=\$PATH:/opt/gnome/bin\n". - " export PATH\n". - " fi\n". - " ;;\n". - " esac\n". + "\n". + "userclientrc=\$HOME/.xinitrc\n". + "sysclientrc=/etc/X11/xinit/xinitrc\n". + "\n". + "if [ -f \"\$userclientrc\" ]; then\n". + " client=\"\$userclientrc\"\n". + "elif [ -f \"\$sysclientrc\" ]; then\n". + " client=\"\$sysclientrc\"\n". "fi\n". - "if [ -x /etc/X11/xinit/xinitrc ]; then\n". - " exec /etc/X11/xinit/xinitrc\n". + "\n". + "if [ -x \"\$client\" ]; then\n". + " exec \"\$client\"\n". "fi\n". - "if [ -f /etc/X11/xinit/xinitrc ]; then\n". - " exec sh /etc/X11/xinit/xinitrc\n". + "if [ -f \"\$client\" ]; then\n". + " exec sh \"\$client\"\n". "fi\n". + "\n". "[ -r \$HOME/.Xresources ] && xrdb \$HOME/.Xresources\n". "xsetroot -solid grey\n". "xterm -geometry 80x24+10+10 -ls -title \"\$VNCDESKTOP Desktop\" &\n". - "twm &\n"); + "if [ -x /usr/bin/twm ]; then\n". + " /usr/bin/twm &\n". + "else\n". + " echo \"No window manager found. You should install a window manager to get properly working VNC session.\"\n". + "fi\n"); $defaultConfig = ("## Supported server options to pass to vncserver upon invocation can be listed\n". ++++++ vnc-httpd.susefirewall ++++++ ## Name: VNC mini-HTTP server ## Description: Opens the VNC HTTP ports so that browsers can connect. TCP="5800:5899" ++++++ vnc-server.susefirewall ++++++ ## Name: VNC ## Description: Opens VNC server ports so that viewers can connect. TCP="5900:5999" ++++++ vnc.pam ++++++ #%PAM-1.0 auth include common-auth account include common-account password include common-password session include common-session ++++++ vnc.reg ++++++ ############################################################################# # # OpenSLP registration file # # register VNC remote logins via kdm # You need also to allow remote logins # ############################################################################# # Register VNC service for krdc (KDE VNC client in kdenetwork) service:remotedesktop.kde:vnc://$HOSTNAME:5901,en,65535 tcp-port=5901 description=VNC remote login [1024x768] # Register VNC service for krdc (KDE VNC client in kdenetwork) service:remotedesktop.kde:vnc://$HOSTNAME:5902,en,65535 tcp-port=5902 description=VNC remote login [1280x1024] # Register VNC service for krdc (KDE VNC client in kdenetwork) service:remotedesktop.kde:vnc://$HOSTNAME:5903,en,65535 tcp-port=5903 description=VNC remote login [1600x1200] # Register VNC service for Java clients # Can be used with every Web browser with enabled Java service:remotedesktop.java:http://$HOSTNAME:5801,en,65535 tcp-port=5801 description=VNC remote login [1024x768] # Register VNC service for Java clients # Can be used with every Web browser with enabled Java service:remotedesktop.java:http://$HOSTNAME:5802,en,65535 tcp-port=5802 description=VNC remote login [1280x1024] # Register VNC service for Java clients # Can be used with every Web browser with enabled Java service:remotedesktop.java:http://$HOSTNAME:5803,en,65535 tcp-port=5803 description=VNC remote login [1600x1200] ++++++ vncpasswd.arg ++++++ #!/bin/sh # Compatibility replacement for vncpasswd.arg. if [ $# -ne 2 ]; then echo "Usage: $0 file password" exit 1 fi echo "$2" | vncpasswd -f > "$1" ++++++ with-vnc-key.sh ++++++ #!/bin/bash # Wrapper that makes sure /etc/vnc/tls.{key,cert} exist before executing given command. TLSKEY=/etc/vnc/tls.key TLSCERT=/etc/vnc/tls.cert if test -s $TLSKEY -a -s $TLSCERT; then # Execute the command we were given. exec "$@" fi ( # Wait for lock on the key file. We must not proceed while someone else is creating it. flock 200 # If the key file doesn't exist or has zero size (because it doubles as lock), generate it. if ! test -s $TLSKEY ; then (umask 077 && openssl genrsa -out $TLSKEY 2048) >&200 chown vnc:vnc $TLSKEY fi # If the cert file doesn't exist, generate it. if ! test -e $TLSCERT ; then # Keeping it short, because hostname could be long and max CN is 64 characters CN="VNC service on `hostname`" CN=${CN:0:64} openssl req -new -x509 -extensions usr_cert -key $TLSKEY -out $TLSCERT -days 7305 -subj "/CN=$CN/" chown vnc:vnc $TLSCERT fi ) 200>>$TLSKEY 2>/dev/null # Execute the command we were given. exec "$@" ++++++ x11vnc ++++++ #!/usr/bin/env python # This is wrapper for x0vncserver that translate most common x11vnc arguments # to x0vncserver's arguments import argparse import socket import os import sys def is_port_free(port): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('', port)) sock.close() return True except socket.error as e: return False def find_free_port(starting_port): for port in range(starting_port, 6000): if is_port_free(port): return port return None parser = argparse.ArgumentParser(add_help=False) parser.add_argument('-help', '-h', action='help') parser.add_argument('--version', '-V', action='store_true') parser.add_argument('-storepasswd', nargs=2) parser.add_argument('-display') parser.add_argument('-auth') parser.add_argument('-N', action='store_true') parser.add_argument('-rfbport', type=int) parser.add_argument('-autoport', type=int, default=5900) parser.add_argument('-6', dest='yes6', action='store_true') parser.add_argument('-no6', action='store_true') #parser.add_argument('-once', action='store_true') # TODO: Add support to x0vncserver parser.add_argument('-forever', '-many', action='store_true') parser.add_argument('-viewonly', action='store_true') #parser.add_argument('-shared', action='store_true') # TODO? parser.add_argument('-alwaysshared', action='store_true') parser.add_argument('-nevershared', action='store_true') parser.add_argument('-dontdisconnect', action='store_true') #parser.add_argument('-timeout', nargs=1, type=int) # TODO? parser.add_argument('-clip') parser.add_argument('-deferupdate', type=int) parser.add_argument('-noshm', action='store_true') #parser.add_argument('-allow', nargs=1) # TODO? #parser.add_argument('-localhost') # TODO? parser.add_argument('-rfbauth') parser.add_argument('-nopw', action='store_true') parser.add_argument('-unixpw') # Accepted, but ignored arguments ignored_arguments = ['-v', '-verbose', '-q', '-quiet'] parser.add_argument(*ignored_arguments, dest='ignored_argument', action='store_true') print('Warning: x11vnc is deprecated in favor of x0vncserver.') print(' This is a wrapper that maps the most common set of x11vnc') print(' arguments to x0vncserver arguments.') print() print(' Use x0vncserver directly if you want encrypted connection.') print() args = parser.parse_args() # Warnings if args.ignored_argument: print('Warning: x11vnc wrapper accepts but ignores following arguments:') print(', '.join(ignored_arguments)) # vncpasswd if args.storepasswd: (password, passwdfile) = args.storepasswd os.execlp('vncpasswd.arg', 'vncpasswd.arg', passwdfile, password) # x0vncserver new_args = ['x0vncserver'] default_security_type = 'None' security_type = default_security_type if args.version: new_args.append('-version') if args.display: new_args.append('-display') new_args.append(args.display) if args.auth: os.environ['XAUTHORITY'] = args.auth if args.N: display = args.display or os.environ['DISPLAY'] if not display: print('No display set') sys.exit(1) port = int(display.split(':')[-1]) + 5900 if is_port_free(port): new_args.append('-rfbport') new_args.append(str(port)) else: print('Port %d is already used'%port) sys.exit(1) if args.rfbport: new_args.append('-rfbport') new_args.append(str(args.rfbport)) else: port = find_free_port(args.autoport) new_args.append('-rfbport') new_args.append(str(port)) if args.yes6: new_args.append('-UseIPv6') if args.no6: new_args.append('-UseIPv6=0') if args.forever: # This is default in x0vncserver pass if args.viewonly: new_args.append('-AcceptKeyEvents=0') new_args.append('-AcceptPointerEvents=0') new_args.append('-AcceptCutText=0') new_args.append('-AcceptSetDesktopSize=0') if args.alwaysshared: new_args.append('-AlwaysShared') if args.nevershared: new_args.append('-NeverShared') if args.dontdisconnect: new_args.append('-DisconnectClients=0') else: new_args.append('-DisconnectClients') if args.clip: new_args.append('-Geometry') new_args.append(args.clip) if args.deferupdate: new_args.append('-DeferUpdate') new_args.append(str(args.deferupdate)) if args.noshm: new_args.append('-UseSHM=0') if args.rfbauth: security_type = 'VncAuth' new_args.append('-PasswordFile') new_args.append(args.rfbauth) if args.unixpw: security_type = 'Plain' new_args.append('-PlainUsers') new_args.append(args.unixpw) new_args.append('-SecurityTypes') new_args.append(security_type) if not args.nopw: # Note: This is the same warning as the original x11vnc gives if security_type == default_security_type: print(""" #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# #@ @# #@ ** WARNING ** WARNING ** WARNING ** WARNING ** @# #@ @# #@ YOU ARE RUNNING X11VNC WITHOUT A PASSWORD!! @# #@ @# #@ This means anyone with network access to this computer @# #@ may be able to view and control your desktop. @# #@ @# #@ >>> If you did not mean to do this Press CTRL-C now!! <<< @# #@ @# #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# """) os.execvp('x0vncserver', new_args) ++++++ xvnc-novnc.service ++++++ [Unit] Description=noVNC Web Server Requires=xvnc.target After=xvnc.target [Service] ExecStart=/usr/lib/vnc/with-vnc-key.sh /usr/bin/websockify --key /etc/vnc/tls.key --cert /etc/vnc/tls.cert --web /usr/share/novnc --inetd localhost:5901 User=vnc StandardInput=socket StandardError=syslog ++++++ xvnc-novnc.socket ++++++ [Unit] Description=noVNC Web Server [Socket] ListenStream=5801 Accept=False [Install] WantedBy=sockets.target ++++++ xvnc.socket ++++++ [Unit] Description=Xvnc Server Before=xvnc.target Wants=xvnc.target [Socket] ListenStream=5901 Accept=yes [Install] WantedBy=sockets.target ++++++ xvnc.target ++++++ [Unit] Description=System VNC service ++++++ xvnc@.service ++++++ [Unit] Description=Xvnc Server [Service] ExecStart=/usr/lib/vnc/with-vnc-key.sh /usr/bin/Xvnc -noreset -inetd -once -query localhost -geometry 1024x768 -securitytypes X509None,None -X509Key /etc/vnc/tls.key -X509Cert /etc/vnc/tls.cert -log *:syslog:30 -extension MIT-SHM User=vnc StandardInput=socket StandardOutput=socket StandardError=syslog