diff --git a/.travis.yml b/.travis.yml index 2b70c259..f8f036f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,25 +10,40 @@ branches: except: - /^pyup-/ +cache: + directories: + - $HOME/docker + env: global: # QUAY_USERNAME and QUAY_PASSWORD for docker image upload - secure: "lKaTzEL6UNiEfp+BWLOUILG9BMtjwEMpwt6Yag0cQGHix7qJ/ElZ0t3oFw6ZwuDmA5qceAXIdxHLUK9HGVI2MloLk8czGhjvtfJ4XhOxtEJRQ0VkDGPsKN4cfhB4ZjGo6GAPtNqStMyNiY7BZuTrZa7coDLCoUeYcOmTpi6pmd1rrkk725B9QCTuhFHbPhkuL2yu/Jk6WxkHJBKjmuZek+iQa7lRItgMrG0/319PXLvwIGGl00nLFy+Ly5Ciwzux4wuHLTySZQKu0H9FX81A7smM0FW/42kg3ckGa2qLxRw/Pi8Nm/aIk8LD0QXzI5N7HhFfidOTgDS8Mt1HgfxmTk4wUXZ/KvCCshqjimzMc/s9i9wPZX9UqqcfrpZkmwz8dzhm1bndN45ZOCy6xAYT6dzf8T4mLMDjVWSW4+DUoW4sYHRLVujjcMk7ybcwGV43VruPTJnc8XVAhT+VIMQkoPjhQmTOn8h82LRNGYtLa5RReCh9OPKVYB2Quz18FXMWgFt7A6VWudL0c7/8CusLvuo+pLcxt9pnV40rvu1YEohpEj8qR/qTSaDUBZM0J9SVf5zrZR80pZUnXkDF8nm+mcLOTley3YWipU19lCR7dzVyCAiQdVAuNPdnyem3Yk8enGkAJbfLd6eaIDs+p73D0JXh1Nx1px1movVLQH3ohIw=" - secure: "w1614pomHLltkBhqWM2bOvbymFWIWKqSqqIBDvaNn9tbQScioItJoELBT7g7+cD7nyU7OvpQ1U2fk0xVkCeNvYU0xS1vP4o/VnZRpup7f7Tkiq+2rf4fjwYr3HHnJjwak1l9bsw6FkgzKaVvSdiUJHMVxiIuLd3fVozR7qjBBhTDxSlWGOpSgd+ttpgMZwU5zQjdaVQr1D7E8M0979ZnWMrNRyLiAUeHaPILS815b+ijgqR+i5nmu0/FTCGM9Ik4KIzIfWq8AdfPdbRiq8c+LrrTPfyKcIQJaHmfduYRM4LycGWwzkXFBNtLrJ7uFLG9RDVemOHuHOWIJX8qCUIV4XuESXxH3fUQr6r+yxquTJbzXxNtoaLa6tBOTQWKDrRjT4z9Mf9Im14F2V59EUDoQowHx5bjunOH5wg3ruYNKYYBFRYra5kx0CkKrqFBzyl8fTUEQLyx1HWTVUC1WTXEeD/aFKOSIxW5DxZr5W4LLlW2+Raa52ZzY28Q6AdueFQCRzoJ70/GsJRlSsBdWNOHN4gSp1cZuToLWY15y64QhAMVDpikB+V4hmkbceLiTqeWzTStNL1sa32RHr6i/9zeFZw1pMD1+eOg9x6fgODfh2sqr/zPbu2oONsHnc4D2jwsEax4o+Dv5QHLvK7jdyWUmu47a9QReoexXK60jZXs3CA=" - -matrix: +jobs: include: - - env: PLATFORM="i686" - - env: PLATFORM="x86_64" - -script: - - PLATFORM=$PLATFORM TRAVIS_COMMIT=$TRAVIS_COMMIT ./build.sh - - -deploy: - provider: script - script: docker/deploy.sh - on: - branch: master - repo: pypa/manylinux + - stage: "Patch glibc" + env: + - PLATFORM="x86_64" + before_install: + # Load cached docker images + - if [[ -d $HOME/docker ]]; then ls $HOME/docker/*.tar.gz | xargs -I {file} sh -c "zcat {file} | docker load"; fi + script: + - PLATFORM=$PLATFORM TRAVIS_COMMIT=$TRAVIS_COMMIT ./build.sh glibc_only + before_cache: + # Save tagged docker images + - mkdir -p $HOME/docker && docker images -a --filter='dangling=false' --format '{{.Repository}}:{{.Tag}} {{.ID}}' | grep 'centos-with-vsyscall:latest' | xargs -n 2 -t sh -c 'test -e $HOME/docker/$1.tar.gz || docker save $0 | gzip -2 > $HOME/docker/$1.tar.gz' + - stage: "Build manylinux images" + env: + - PLATFORM="x86_64" + before_install: + # Load cached docker images + - if [[ -d $HOME/docker ]]; then ls $HOME/docker/*.tar.gz | xargs -I {file} sh -c "zcat {file} | docker load"; fi + script: + - PLATFORM=$PLATFORM TRAVIS_COMMIT=$TRAVIS_COMMIT ./build.sh + deploy: + provider: script + script: docker/deploy.sh + on: + branch: master + repo: pypa/manylinux diff --git a/build.sh b/build.sh index c1c444d5..c2301537 100755 --- a/build.sh +++ b/build.sh @@ -3,5 +3,18 @@ # Stop at any error, show all commands set -ex + +if [ $PLATFORM == x86_64 ] || [ "$1" == "glibc_only" ]; then + # Output something every 10 minutes or Travis kills the job + while sleep 9m; do echo -n -e " \b"; done & + docker build --rm -t centos-with-vsyscall:latest --cache-from centos-with-vsyscall:latest --target centos-with-vsyscall -f docker/glibc/Dockerfile docker/glibc/ + # Killing background sleep loop + kill %1 + if [ "$1" == "glibc_only" ]; then + exit 0 + fi + docker build --rm -t quay.io/pypa/manylinux2010_centos-6-no-vsyscall --cache-from quay.io/pypa/manylinux2010_centos-6-no-vsyscall:latest --cache-from centos-with-vsyscall:latest -f docker/glibc/Dockerfile docker/glibc/ +fi + docker/build_scripts/prefetch.sh openssl curl -docker build --rm -t quay.io/pypa/manylinux1_$PLATFORM:$TRAVIS_COMMIT -f docker/Dockerfile-$PLATFORM docker/ +docker build --rm -t quay.io/pypa/manylinux2010_$PLATFORM:$TRAVIS_COMMIT -f docker/Dockerfile-$PLATFORM docker/ diff --git a/docker/Dockerfile-i686 b/docker/Dockerfile-i686 deleted file mode 100644 index 2d38d493..00000000 --- a/docker/Dockerfile-i686 +++ /dev/null @@ -1,20 +0,0 @@ -FROM phusion/centos-5-32 -MAINTAINER The ManyLinux project - -ENV LC_ALL=en_US.UTF-8 -ENV LANG=en_US.UTF-8 -ENV LANGUAGE en_US.UTF-8 -ENV PATH /opt/rh/devtoolset-2/root/usr/bin:$PATH -ENV LD_LIBRARY_PATH /opt/rh/devtoolset-2/root/usr/lib64:/opt/rh/devtoolset-2/root/usr/lib:/usr/local/lib64:/usr/local/lib -ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig - -COPY build_scripts /build_scripts -COPY sources / -RUN linux32 bash build_scripts/build.sh && rm -r build_scripts - -ENV SSL_CERT_FILE=/opt/_internal/certs.pem - -# Run 32-bit uname selection on way into image -ENTRYPOINT ["linux32"] - -CMD ["/bin/bash"] diff --git a/docker/Dockerfile-x86_64 b/docker/Dockerfile-x86_64 index b921c1aa..ca4c5d94 100644 --- a/docker/Dockerfile-x86_64 +++ b/docker/Dockerfile-x86_64 @@ -1,12 +1,13 @@ -FROM centos:5 -MAINTAINER The ManyLinux project +# See docker/glibc/ +FROM quay.io/pypa/manylinux2010_centos-6-no-vsyscall +LABEL maintainer="The ManyLinux project" ENV LC_ALL en_US.UTF-8 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US.UTF-8 -ENV PATH /opt/rh/devtoolset-2/root/usr/bin:$PATH -ENV LD_LIBRARY_PATH /opt/rh/devtoolset-2/root/usr/lib64:/opt/rh/devtoolset-2/root/usr/lib:/usr/local/lib64:/usr/local/lib -ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig +ENV PATH /opt/rh/devtoolset-8/root/usr/bin:$PATH +ENV LD_LIBRARY_PATH /opt/rh/devtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib:/opt/rh/devtoolset-8/root/usr/lib64/dyninst:/opt/rh/devtoolset-8/root/usr/lib/dyninst:/usr/local/lib64:/usr/local/lib +ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig COPY build_scripts /build_scripts COPY sources / diff --git a/docker/build_scripts/build.sh b/docker/build_scripts/build.sh index 3a9fdfb8..8ad80914 100755 --- a/docker/build_scripts/build.sh +++ b/docker/build_scripts/build.sh @@ -10,20 +10,25 @@ MY_DIR=$(dirname "${BASH_SOURCE[0]}") # Dependencies for compiling Python that we want to remove from # the final image after compiling Python -# GPG installed to verify signatures on Python source tarballs. -PYTHON_COMPILE_DEPS="zlib-devel bzip2-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel gpg libffi-devel" - -# Libraries that are allowed as part of the manylinux1 profile -MANYLINUX1_DEPS="glibc-devel libstdc++-devel glib2-devel libX11-devel libXext-devel libXrender-devel mesa-libGL-devel libICE-devel libSM-devel ncurses-devel" - -# Centos 5 is EOL and is no longer available from the usual mirrors, so switch -# to http://vault.centos.org -# From: https://github.com/rust-lang/rust/pull/41045 -# The location for version 5 was also removed, so now only the specific release -# (5.11) can be referenced. -sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf -sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo -sed -i 's/#\(baseurl.*\)mirror.centos.org\/centos\/$releasever/\1vault.centos.org\/5.11/' /etc/yum.repos.d/*.repo +PYTHON_COMPILE_DEPS="zlib-devel bzip2-devel expat-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel" + +# Libraries that are allowed as part of the manylinux2010 profile +# Extract from PEP: https://www.python.org/dev/peps/pep-0571/#the-manylinux2010-policy +# On RPM-based systems, they are provided by these packages: +# Package: Libraries +# glib2: libglib-2.0.so.0, libgthread-2.0.so.0, libgobject-2.0.so.0 +# glibc: libresolv.so.2, libutil.so.1, libnsl.so.1, librt.so.1, libcrypt.so.1, libpthread.so.0, libdl.so.2, libm.so.6, libc.so.6 +# libICE: libICE.so.6 +# libX11: libX11.so.6 +# libXext: libXext.so.6 +# libXrender: libXrender.so.1 +# libgcc: libgcc_s.so.1 +# libstdc++: libstdc++.so.6 +# mesa: libGL.so.1 +# +# PEP is missing the package for libSM.so.6 for RPM based system +# Install development packages (except for libgcc which is provided by gcc install) +MANYLINUX2010_DEPS="glibc-devel libstdc++-devel glib2-devel libX11-devel libXext-devel libXrender-devel mesa-libGL-devel libICE-devel libSM-devel" # Get build utilities source $MY_DIR/build_utils.sh @@ -41,21 +46,8 @@ echo "multilib_policy=best" >> /etc/yum.conf # Decided not to clean at this point: https://github.com/pypa/manylinux/pull/129 yum -y update -# EPEL support -yum -y install wget -# https://dl.fedoraproject.org/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm -cp $MY_DIR/epel-release-5-4.noarch.rpm . -check_sha256sum epel-release-5-4.noarch.rpm $EPEL_RPM_HASH - -# Dev toolset (for LLVM and other projects requiring C++11 support) -wget -q http://people.centos.org/tru/devtools-2/devtools-2.repo -check_sha256sum devtools-2.repo $DEVTOOLS_HASH -mv devtools-2.repo /etc/yum.repos.d/devtools-2.repo -rpm -Uvh --replacepkgs epel-release-5*.rpm -rm -f epel-release-5*.rpm - -# from now on, we shall only use curl to retrieve files -yum -y erase wget +# Software collection (for devtoolset-8) and EPEL support (for cmake28 & yasm) +yum -y install centos-release-scl https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm # Development tools and libraries yum -y install \ @@ -63,17 +55,18 @@ yum -y install \ bison \ bzip2 \ cmake28 \ - devtoolset-2-binutils \ - devtoolset-2-gcc \ - devtoolset-2-gcc-c++ \ - devtoolset-2-gcc-gfortran \ + devtoolset-8-binutils \ + devtoolset-8-gcc \ + devtoolset-8-gcc-c++ \ + devtoolset-8-gcc-gfortran \ diffutils \ - expat-devel \ gettext \ - kernel-devel-`uname -r` \ file \ + kernel-devel-`uname -r` \ + libffi-devel \ make \ patch \ + perl-devel \ unzip \ which \ yasm \ @@ -147,18 +140,39 @@ rm -rf patchelf.tar.gz patchelf-$PATCHELF_VERSION ln -s $PY36_BIN/auditwheel /usr/local/bin/auditwheel +# HACK: The newly compiled and installed curl messes with the system's +# py2.6 installation, on which yum depends. Work around it by +# rewiring libcurl.so specifically for yum. /usr/local/bin/ has higher +# priority on the PATH than /usr/bin/ +cat <<'EOF' > /usr/local/bin/yum && chmod +x /usr/local/bin/yum +#!/bin/bash +if [ "x$(arch)" != xi686 ]; then + LD_PRELOAD=/usr/lib64/libcurl.so.4 +else + LD_PRELOAD=/usr/lib/libcurl.so.4 +fi +export LD_PRELOAD +/usr/bin/yum "$@" +EOF +# the above might not shadow the real yum just yet, so call hash to be +# sure: +type yum +hash yum + + # Clean up development headers and other unnecessary stuff for # final image yum -y erase \ avahi \ bitstream-vera-fonts \ freetype \ + gettext \ gtk2 \ hicolor-icon-theme \ libX11 \ wireless-tools \ - ${PYTHON_COMPILE_DEPS} > /dev/null 2>&1 -yum -y install ${MANYLINUX1_DEPS} + ${PYTHON_COMPILE_DEPS} > /dev/null 2>&1 +yum -y install ${MANYLINUX2010_DEPS} yum -y clean all > /dev/null 2>&1 yum list installed @@ -180,7 +194,7 @@ find /opt/_internal -depth \ for PYTHON in /opt/python/*/bin/python; do # Smoke test to make sure that our Pythons work, and do indeed detect as # being manylinux compatible: - $PYTHON $MY_DIR/manylinux1-check.py + $PYTHON $MY_DIR/manylinux-check.py # Make sure that SSL cert checking works $PYTHON $MY_DIR/ssl-check.py done diff --git a/docker/build_scripts/build_env.sh b/docker/build_scripts/build_env.sh index 6d06fe91..7819edd6 100644 --- a/docker/build_scripts/build_env.sh +++ b/docker/build_scripts/build_env.sh @@ -37,5 +37,5 @@ GIT_HASH=ba2fed9d02e424b735e035c4f2b0bdb168ef0df7e35156b5051d900dc7247787 GIT_DOWNLOAD_URL=https://github.com/git/git/archive GET_PIP_URL=https://bootstrap.pypa.io/get-pip.py -EPEL_RPM_HASH=0dcc89f9bf67a2a515bad64569b7a9615edc5e018f676a578d5fd0f17d3c81d4 +EPEL_RPM_HASH=e5ed9ecf22d0c4279e92075a64c757ad2b38049bcf5c16c4f2b75d5f6860dc0d DEVTOOLS_HASH=a8ebeb4bed624700f727179e6ef771dafe47651131a00a78b342251415646acc diff --git a/docker/build_scripts/build_utils.sh b/docker/build_scripts/build_utils.sh index dd0780e2..c84ed8cb 100755 --- a/docker/build_scripts/build_utils.sh +++ b/docker/build_scripts/build_utils.sh @@ -54,10 +54,7 @@ function do_cpython_build { if [ -e ${prefix}/bin/python3 ]; then ln -s python3 ${prefix}/bin/python fi - # --force-reinstall is to work around: - # https://github.com/pypa/pip/issues/5220 - # https://github.com/pypa/get-pip/issues/19 - ${prefix}/bin/python get-pip.py --force-reinstall + ${prefix}/bin/python get-pip.py if [ -e ${prefix}/bin/pip3 ] && [ ! -e ${prefix}/bin/pip ]; then ln -s pip3 ${prefix}/bin/pip fi diff --git a/docker/build_scripts/epel-release-5-4.noarch.rpm b/docker/build_scripts/epel-release-5-4.noarch.rpm deleted file mode 100644 index a65162a8..00000000 Binary files a/docker/build_scripts/epel-release-5-4.noarch.rpm and /dev/null differ diff --git a/docker/build_scripts/manylinux1-check.py b/docker/build_scripts/manylinux-check.py similarity index 82% rename from docker/build_scripts/manylinux1-check.py rename to docker/build_scripts/manylinux-check.py index fa77ef43..8c1031f9 100644 --- a/docker/build_scripts/manylinux1-check.py +++ b/docker/build_scripts/manylinux-check.py @@ -1,6 +1,6 @@ # Logic copied from PEP 513 -def is_manylinux1_compatible(): +def is_manylinux2010_compatible(): # Only Linux, and only x86-64 / i686 from distutils.util import get_platform if get_platform() not in ["linux-x86_64", "linux-i686"]: @@ -14,8 +14,8 @@ def is_manylinux1_compatible(): # Fall through to heuristic check below pass - # Check glibc version. CentOS 5 uses glibc 2.5. - return have_compatible_glibc(2, 5) + # Check glibc version. CentOS 6 uses glibc 2.12. + return have_compatible_glibc(2, 12) def have_compatible_glibc(major, minimum_minor): import ctypes @@ -45,9 +45,9 @@ def have_compatible_glibc(major, minimum_minor): return True import sys -if is_manylinux1_compatible(): - print("%s is manylinux1 compatible" % (sys.executable,)) +if is_manylinux2010_compatible(): + print("%s is manylinux2010 compatible" % (sys.executable,)) sys.exit(0) else: - print("%s is NOT manylinux1 compatible" % (sys.executable,)) + print("%s is NOT manylinux2010 compatible" % (sys.executable,)) sys.exit(1) diff --git a/docker/deploy.sh b/docker/deploy.sh index 471f160a..34791d0a 100755 --- a/docker/deploy.sh +++ b/docker/deploy.sh @@ -1,5 +1,5 @@ #!/bin/bash docker login -u $QUAY_USERNAME -p $QUAY_PASSWORD quay.io -tag="quay.io/pypa/manylinux1_$PLATFORM" +tag="quay.io/pypa/manylinux2010_$PLATFORM" docker tag ${tag}:${TRAVIS_COMMIT} ${tag}:latest docker push ${tag}:latest diff --git a/docker/glibc/Dockerfile b/docker/glibc/Dockerfile new file mode 100644 index 00000000..25bf468b --- /dev/null +++ b/docker/glibc/Dockerfile @@ -0,0 +1,11 @@ +FROM centos:6 as centos-with-vsyscall + +COPY ./build_scripts /build_scripts +RUN bash /build_scripts/rebuild-glibc-without-vsyscall.sh + +FROM centos:6 +LABEL maintainer="The Manylinux project" + +COPY --from=centos-with-vsyscall /rpms /rpms + +RUN yum -y install /rpms/* && rm -rf /rpms diff --git a/docker/glibc/README.rst b/docker/glibc/README.rst new file mode 100644 index 00000000..c4b0fc37 --- /dev/null +++ b/docker/glibc/README.rst @@ -0,0 +1,79 @@ +centos-6-no-vsyscall +==================== + +*Summary*: Because of +https://mail.python.org/pipermail/wheel-builders/2016-December/000239.html, +this a CentOS 6.10 Docker image that rebuilds ``glibc`` without +*vsyscall* is necessary to reliably run ``manylinux2010`` on 64-bit +hosts. This requires building the image on a system with +``vsyscall=emulate`` but allows the resulting container to run on +systems with ``vsyscall=none`` or ``vsyscall=emulate``. + +*vsyscall* is an antiquated optimization for a small number of +frequently-used system calls. A vsyscall-enabled Linux kernel maps a +read-only page of data and system calls into a process' memory at a +fixed address. These system calls can then be invoked by +dereferencing a function pointers to fixed offsets in that page, +saving a relatively expensive context switch. [1]_ + +Unfortunately, because the code and its location in memory are fixed +and well-known, the vsyscall mechanism has become a source of gadgets +for ROP attacks (specifically, Sigreturn-Oriented Programs). [2]_ +Linux 3.1 introduced vsyscall emulation that prevents attackers from +jumping into the middle of the system calls' code at the expense of +speed, as well as the ability to disable it entirely. [3]_ [4]_ The +vsyscall mechanism could not be eliminated at the time because +``glibc`` versions earlier than 2.14 contained hard-coded references +to the fixed memory address, specifically in ``time(2)``. [5]_ These +segfault when attempting to issue a vsyscall-optimized system call +against a kernel that has disabled it. + +Linux introduced a "virtual dynamic shared object" (vDSO) that +achieves the same high-speed, in-process system call mechanism via +shared objects sometime before the kernel's migration to git. While +old itself, vDSO 's presentation as a shared library allows it to +benefit from ASLR on modern systems, making it no more amenable to ROP +gadgets than any other shared library. ``glibc`` only switched over +completely to vDSO as of glibc 2.25, so until recently vsyscall +emulation has remained on for most kernels. [6]_ Furthermore, i686 +does not use vsyscall at all, so no version of ``glibc`` requires +patching on that architecture. + +At the same time, vsyscall emulation still exposed values useful to +ROP attacks, so Linux 4.4 added a compilation option to disable +it. [7]_ [8]_ Distributions are beginning to ship kernels configured +without vsyscall, and running CentOS 5 (``glibc`` 2.5) or 6 (``glibc`` +2.12) Docker containers on these distributions indeed causes segfaults +without ``vsyscall=emulate`` [9]_ [10]_. CentOS 6, however, is +supported until 2020. It is likely that more and more distributions +will ship with ``CONFIG_LEGACY_VSYSCALL_NONE``; if managed CI services +like Travis make this switch, developers will be unable to build +``manylinux2010`` wheels with our Docker image. + +Fortunately, vsyscall is merely an optimization, and patches that +remove it can be backported to glibc 2.12 and the library recompiled. +The result is this Docker image. It can be run on kernels regardless +of their vsyscall configuration because executable and libraries on +CentOS are dynamically linked against glibc. Libraries built on this +image are unaffected because: + +a) the kernel only maps vsyscall pages into processes; +b) only glibc used the vsyscall interface directly, and it's + included in manylinux2010's whitelist policy. + +Developers who build this vsyscall-less Docker image itself, however, +must do so on a system with ``vsyscall=emulate``. + +References: +=========== + +.. [1] https://lwn.net/Articles/446528/ +.. [2] http://www.cs.vu.nl/~herbertb/papers/srop_sp14.pdf +.. [3] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5cec93c216db77c45f7ce970d46283bcb1933884 +.. [4] https://www.kernel.org/pub/linux/kernel/v3.x/ChangeLog-3.1 +.. [5] https://sourceware.org/git/?p=glibc.git;a=blob;f=ChangeLog;h=3a6abda7d07fdaa367c48a9274cc1c08498964dc;hb=356f8bc660a154a07b03da7c536831da5c8f74fe +.. [6] https://sourceware.org/git/?p=glibc.git;a=blob;f=ChangeLog;h=6037fef737f0338a84c6fb564b3b8dc1b1221087;hb=58557c229319a3b8d2eefdb62e7df95089eabe37 +.. [7] https://googleprojectzero.blogspot.fr/2015/08/three-bypasses-and-fix-for-one-of.html +.. [8] https://outflux.net/blog/archives/2016/09/27/security-things-in-linux-v4-4/ +.. [9] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=852620#20 +.. [10] https://github.com/CentOS/sig-cloud-instance-images/issues/62 diff --git a/docker/glibc/build_scripts/CentOS-source.repo b/docker/glibc/build_scripts/CentOS-source.repo new file mode 100644 index 00000000..5501f550 --- /dev/null +++ b/docker/glibc/build_scripts/CentOS-source.repo @@ -0,0 +1,7 @@ +[base-source] +name=CentOS-6.10 - Base SRPMS +baseurl=http://vault.centos.org/6.10/os/Source/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6 +priority=1 +enabled=1 diff --git a/docker/glibc/build_scripts/glibc.spec.patch b/docker/glibc/build_scripts/glibc.spec.patch new file mode 100644 index 00000000..c7a3b0f9 --- /dev/null +++ b/docker/glibc/build_scripts/glibc.spec.patch @@ -0,0 +1,29 @@ +diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec +index 9bd07c9..c389711 100644 +--- a/SPECS/glibc.spec ++++ b/SPECS/glibc.spec +@@ -1,6 +1,6 @@ + %define glibcsrcdir glibc-2.12-2-gc4ccff1 + %define glibcversion 2.12 +-%define glibcrelease 1.212%{?dist} ++%define glibcrelease 1.212.1%{?dist} + %define run_glibc_tests 1 + %define auxarches athlon sparcv9v sparc64v alphaev6 + %define xenarches i686 athlon +@@ -279,6 +279,7 @@ + Patch247: glibc-rh1452717-4.patch + Patch248: glibc-rh1504810-1.patch + Patch249: glibc-rh1504810-2.patch ++Patch250: remove-vsyscall.patch + + Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + Obsoletes: glibc-profile < 2.4 +@@ -731,6 +732,7 @@ + %patch247 -p1 + %patch248 -p1 + %patch249 -p1 ++%patch250 -E -p3 + + # A lot of programs still misuse memcpy when they have to use + # memmove. The memcpy implementation below is not tolerant at + diff --git a/docker/glibc/build_scripts/rebuild-glibc-without-vsyscall.sh b/docker/glibc/build_scripts/rebuild-glibc-without-vsyscall.sh new file mode 100644 index 00000000..9b2b570c --- /dev/null +++ b/docker/glibc/build_scripts/rebuild-glibc-without-vsyscall.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# Prep script for x86_64 that recompiles glibc without vsyscalls. + +# Stop at any error, show all commands +set -ex + +# Locate the prep directory +MY_DIR=/$(dirname "${BASH_SOURCE[0]}") + +# glibc versions +ORIGINAL_GLIBC_VERSION=2.12-1.212 +PATCHED_GLIBC_VERSION=2.12-1.212.1 + +# Source RPM topdir +SRPM_TOPDIR=/root/rpmbuild + +# Source RPM download directory +DOWNLOADED_SRPMS=/root/srpms + +# Include the CentOS source RPM repository. +# https://bugs.centos.org/view.php?id=1646 +cp $MY_DIR/CentOS-source.repo /etc/yum.repos.d/CentOS-source.repo + +# Extract and prepare the source +# https://blog.packagecloud.io/eng/2015/04/20/working-with-source-rpms/ +yum -y update +yum -y install yum-utils rpm-build +yum-builddep -y glibc +mkdir $DOWNLOADED_SRPMS +# The glibc RPM's contents are owned by mockbuild +adduser mockbuild +# yumdownloader assumes the current working directory +(cd $DOWNLOADED_SRPMS && yumdownloader --source glibc) +rpm -ivh $DOWNLOADED_SRPMS/glibc-$ORIGINAL_GLIBC_VERSION.el6.src.rpm +# Prepare the source by applying Red Hat and CentOS patches +rpmbuild -bp $SRPM_TOPDIR/SPECS/glibc.spec + +# Copy the vsyscall removal patch into place +cp $MY_DIR/remove-vsyscall.patch $SRPM_TOPDIR/SOURCES +# Patch the RPM spec file so that it uses the vsyscall removal patch +(cd $SRPM_TOPDIR/SPECS && patch -p2 < $MY_DIR/glibc.spec.patch) + +# Build the RPMS +# In case of error, you can `docker commit` to inspect the build.log +rpmbuild -ba $SRPM_TOPDIR/SPECS/glibc.spec >> /var/log/build.log + +mv $SRPM_TOPDIR/RPMS/* /rpms/ + +# Show us what happened last before cleaning up the log +echo ~~~~~~~~~~~~~~~~~~~~~ final lines of the build log ~~~~~~~~~~~~~~~~~~~~~ >/dev/null +tail -n30 /var/log/build.log +rm /var/log/build.log diff --git a/docker/glibc/build_scripts/remove-vsyscall.patch b/docker/glibc/build_scripts/remove-vsyscall.patch new file mode 100644 index 00000000..15f4fdcc --- /dev/null +++ b/docker/glibc/build_scripts/remove-vsyscall.patch @@ -0,0 +1,401 @@ +diff --git a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S +index 22beaec..d1e29da 100644 +--- a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S ++++ b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S +@@ -68,10 +68,6 @@ + #endif + + +-/* For the calculation see asm/vsyscall.h. */ +-#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 +- +- + .globl __lll_lock_wait_private + .type __lll_lock_wait_private,@function + .hidden __lll_lock_wait_private +@@ -250,10 +246,9 @@ __lll_timedlock_wait: + /* Get current time. */ + movq %rsp, %rdi + xorl %esi, %esi +- movq $VSYSCALL_ADDR_vgettimeofday, %rax +- /* This is a regular function call, all caller-save registers +- might be clobbered. */ +- callq *%rax ++ /* This call works because we directly jump to a system call entry ++ which preserves all the registers. */ ++ call JUMPTARGET(__gettimeofday) + + /* Compute relative timeout. */ + movq 8(%rsp), %rax +@@ -402,8 +397,9 @@ __lll_timedwait_tid: + /* Get current time. */ + 2: movq %rsp, %rdi + xorl %esi, %esi +- movq $VSYSCALL_ADDR_vgettimeofday, %rax +- callq *%rax ++ /* This call works because we directly jump to a system call entry ++ which preserves all the registers. */ ++ call JUMPTARGET(__gettimeofday) + + /* Compute relative timeout. */ + movq 8(%rsp), %rax +diff --git a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S +index b6537f9..cf9121d 100644 +--- a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S ++++ b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S +@@ -51,9 +51,6 @@ + orl $FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg + #endif + +-/* For the calculation see asm/vsyscall.h. */ +-#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 +- + + .globl __lll_robust_lock_wait + .type __lll_robust_lock_wait,@function +@@ -220,10 +217,9 @@ __lll_robust_timedlock_wait: + /* Get current time. */ + movq %rsp, %rdi + xorl %esi, %esi +- movq $VSYSCALL_ADDR_vgettimeofday, %rax +- /* This is a regular function call, all caller-save registers +- might be clobbered. */ +- callq *%rax ++ /* This call works because we directly jump to a system call entry ++ which preserves all the registers. */ ++ call JUMPTARGET(__gettimeofday) + + /* Compute relative timeout. */ + movq 8(%rsp), %rax +diff --git a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S +index fecaa50..9ea8353 100644 +--- a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S ++++ b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S +@@ -26,9 +26,6 @@ + + #include + +-/* For the calculation see asm/vsyscall.h. */ +-#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 +- + + .text + +@@ -490,13 +487,11 @@ __pthread_cond_timedwait: + movq __vdso_clock_gettime@GOTPCREL(%rip), %rax + movq (%rax), %rax + PTR_DEMANGLE (%rax) +- jz 26f + call *%rax +- jmp 27f +-# endif +-26: movl $__NR_clock_gettime, %eax ++# else ++ movl $__NR_clock_gettime, %eax + syscall +-27: ++# endif + # ifndef __ASSUME_POSIX_TIMERS + cmpq $-ENOSYS, %rax + je 19f +@@ -510,8 +505,9 @@ __pthread_cond_timedwait: + # else + leaq 24(%rsp), %rdi + xorl %esi, %esi +- movq $VSYSCALL_ADDR_vgettimeofday, %rax +- callq *%rax ++ /* This call works because we directly jump to a system call entry ++ which preserves all the registers. */ ++ call JUMPTARGET(__gettimeofday) + + /* Compute relative timeout. */ + movq 40(%rsp), %rax +@@ -648,8 +644,9 @@ __pthread_cond_timedwait: + /* clock_gettime not available. */ + 19: leaq 32(%rsp), %rdi + xorl %esi, %esi +- movq $VSYSCALL_ADDR_vgettimeofday, %rax +- callq *%rax ++ /* This call works because we directly jump to a system call entry ++ which preserves all the registers. */ ++ call JUMPTARGET(__gettimeofday) + + /* Compute relative timeout. */ + movq 40(%rsp), %rax +diff --git a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S +index 22a4744..f65d976 100644 +--- a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S ++++ b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S +@@ -23,10 +23,6 @@ + #include + #include + +- +-/* For the calculation see asm/vsyscall.h. */ +-#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 +- + .text + + .globl pthread_rwlock_timedrdlock +@@ -123,8 +119,9 @@ pthread_rwlock_timedrdlock: + /* Get current time. */ + movq %rsp, %rdi + xorl %esi, %esi +- movq $VSYSCALL_ADDR_vgettimeofday, %rax +- callq *%rax ++ /* This call works because we directly jump to a system call entry ++ which preserves all the registers. */ ++ call JUMPTARGET(__gettimeofday) + + /* Compute relative timeout. */ + movq 8(%rsp), %rax +diff --git a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S +index 20a9c00..4338e02 100644 +--- a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S ++++ b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S +@@ -23,10 +23,6 @@ + #include + #include + +- +-/* For the calculation see asm/vsyscall.h. */ +-#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 +- + .text + + .globl pthread_rwlock_timedwrlock +@@ -120,8 +116,9 @@ pthread_rwlock_timedwrlock: + /* Get current time. */ + movq %rsp, %rdi + xorl %esi, %esi +- movq $VSYSCALL_ADDR_vgettimeofday, %rax +- callq *%rax ++ /* This call works because we directly jump to a system call entry ++ which preserves all the registers. */ ++ call JUMPTARGET(__gettimeofday) + + /* Compute relative timeout. */ + movq 8(%rsp), %rax +diff --git a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S +index c339494..30e67e2 100644 +--- a/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S ++++ b/BUILD/glibc-2.12-2-gc4ccff1/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S +@@ -24,10 +24,6 @@ + #include + #include + +- +-/* For the calculation see asm/vsyscall.h. */ +-#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 +- + .text + + .globl sem_timedwait +@@ -212,9 +208,10 @@ sem_timedwait: + addq $1, NWAITERS(%r12) + + 7: xorl %esi, %esi +- movq %rsp, %rdi +- movq $VSYSCALL_ADDR_vgettimeofday, %rax +- callq *%rax ++ movq %rsp,%rdi ++ /* This call works because we directly jump to a system call entry ++ which preserves all the registers. */ ++ call JUMPTARGET(__gettimeofday) + + /* Compute relative timeout. */ + movq 8(%rsp), %rax +diff --git a/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/gettimeofday.S b/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/gettimeofday.S +deleted file mode 100644 +index 18ec6db..0000000 +--- a/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/gettimeofday.S ++++ /dev/null +@@ -1,50 +0,0 @@ +-/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library 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 +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, write to the Free +- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +- 02111-1307 USA. */ +- +-#include +-#define _ERRNO_H 1 +-#include +- +-/* For the calculation see asm/vsyscall.h. */ +-#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 +- +- +-ENTRY (__gettimeofday) +- /* Align stack. */ +- sub $0x8, %rsp +- cfi_adjust_cfa_offset(8) +-#ifdef SHARED +- movq __vdso_gettimeofday(%rip), %rax +- PTR_DEMANGLE (%rax) +-#else +- movq $VSYSCALL_ADDR_vgettimeofday, %rax +-#endif +- callq *%rax +- /* Check error return. */ +- cmpl $-4095, %eax +- jae SYSCALL_ERROR_LABEL +- +-L(pseudo_end): +- add $0x8, %rsp +- cfi_adjust_cfa_offset(-8) +- ret +-PSEUDO_END(__gettimeofday) +- +-libc_hidden_def (__gettimeofday) +-weak_alias (__gettimeofday, gettimeofday) +-libc_hidden_weak (gettimeofday) +diff --git a/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/init-first.c b/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/init-first.c +index ead7dbc..08c1ef7 100644 +--- a/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/init-first.c ++++ b/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/init-first.c +@@ -17,6 +17,7 @@ + 02111-1307 USA. */ + + #ifdef SHARED ++# include + # include + # include + +@@ -26,6 +27,8 @@ long int (*__vdso_clock_gettime) (clockid_t, struct timespec *) + __attribute__ ((nocommon)); + strong_alias (__vdso_clock_gettime, __GI___vdso_clock_gettime attribute_hidden) + ++extern int __gettimeofday (struct timeval *__tv, struct timezone *__tz); ++ + + static inline void + _libc_vdso_platform_setup (void) +@@ -33,10 +36,9 @@ _libc_vdso_platform_setup (void) + PREPARE_VERSION (linux26, "LINUX_2.6", 61765110); + + void *p = _dl_vdso_vsym ("gettimeofday", &linux26); +- /* If the vDSO is not available we fall back on the old vsyscall. */ +-#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000ul ++ /* If the vDSO is not available we fall back on the syscall. */ + if (p == NULL) +- p = (void *) VSYSCALL_ADDR_vgettimeofday; ++ p = __gettimeofday; + PTR_MANGLE (p); + __vdso_gettimeofday = p; + +diff --git a/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/sched_getcpu.S b/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/sched_getcpu.S +deleted file mode 100644 +index a950990..0000000 +--- a/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/sched_getcpu.S ++++ /dev/null +@@ -1,50 +0,0 @@ +-/* Copyright (C) 2007 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library 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 +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, write to the Free +- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +- 02111-1307 USA. */ +- +-#include +-#include +-#define _ERRNO_H 1 +-#include +- +-/* For the calculation see asm/vsyscall.h. */ +-#define VSYSCALL_ADDR_vgetcpu 0xffffffffff600800 +- +- +-ENTRY (sched_getcpu) +- /* Align stack and create local variable for result. */ +- sub $0x8, %rsp +- cfi_adjust_cfa_offset(8) +- +- movq %rsp, %rdi +- xorl %esi, %esi +- movl $VGETCPU_CACHE_OFFSET, %edx +- addq %fs:0, %rdx +- +- movq $VSYSCALL_ADDR_vgetcpu, %rax +- callq *%rax +- +- cmpq $-4095, %rax +- jae SYSCALL_ERROR_LABEL +- +- movl (%rsp), %eax +- +-L(pseudo_end): +- add $0x8, %rsp +- cfi_adjust_cfa_offset(-8) +- ret +-PSEUDO_END(sched_getcpu) +diff --git a/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/time.S b/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/time.S +deleted file mode 100644 +index e3f3268..0000000 +--- a/BUILD/glibc-2.12-2-gc4ccff1/sysdeps/unix/sysv/linux/x86_64/time.S ++++ /dev/null +@@ -1,42 +0,0 @@ +-/* Copyright (C) 2001,02, 2003 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library 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 +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, write to the Free +- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +- 02111-1307 USA. */ +- +-#include +-#define _ERRNO_H 1 +-#include +- +-/* For the calculation see asm/vsyscall.h. */ +-#define VSYSCALL_ADDR_vtime 0xffffffffff600400 +- +- +-/* Return the current time as a `time_t' and also put it in *T if T is +- not NULL. Time is represented as seconds from Jan 1 00:00:00 1970. */ +- +-ENTRY (time) +- /* Align stack. */ +- sub $0x8, %rsp +- cfi_adjust_cfa_offset(8) +- +- movq $VSYSCALL_ADDR_vtime, %rax +- callq *%rax +- +- add $0x8, %rsp +- cfi_adjust_cfa_offset(-8) +- ret +-PSEUDO_END_NOERRNO(time) +-libc_hidden_def (time)