Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manylinux2010 #182

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ matrix:
- env: PLATFORM="x86_64"

script:
- PLATFORM=$PLATFORM TRAVIS_COMMIT=$TRAVIS_COMMIT ./build.sh
- PLATFORM=$PLATFORM TRAVIS_COMMIT=$TRAVIS_COMMIT travis_wait 60 ./build.sh


deploy:
Expand Down
5 changes: 4 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
set -ex

docker/build_scripts/prefetch.sh openssl curl
docker build --rm -t quay.io/pypa/manylinux1_$PLATFORM:$TRAVIS_COMMIT -f docker/Dockerfile-$PLATFORM docker/
if [ $PLATFORM == x86_64 ]; then
docker build --rm -t quay.io/pypa/manylinux2010_centos-6-no-vsyscall -f docker/glibc/Dockerfile docker/glibc/
fi
docker build --rm -t quay.io/pypa/manylinux2010_$PLATFORM:$TRAVIS_COMMIT -f docker/Dockerfile-$PLATFORM docker/
docker system prune -f
6 changes: 4 additions & 2 deletions docker/Dockerfile-i686
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM phusion/centos-5-32
MAINTAINER The ManyLinux project
FROM i386/centos:6
LABEL maintainer="The ManyLinux project"

ENV LC_ALL=en_US.UTF-8
ENV LANG=en_US.UTF-8
Expand All @@ -10,6 +10,8 @@ ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

COPY build_scripts /build_scripts
COPY sources /
COPY /build_scripts/linux32 /usr/bin/linux32
RUN chmod +x /usr/bin/linux32
RUN linux32 bash build_scripts/build.sh && rm -r build_scripts

ENV SSL_CERT_FILE=/opt/_internal/certs.pem
Expand Down
7 changes: 4 additions & 3 deletions docker/Dockerfile-x86_64
Original file line number Diff line number Diff line change
@@ -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 PKG_CONFIG_PATH /usr/local/lib/pkgconfig

COPY build_scripts /build_scripts
COPY sources /
Expand Down
59 changes: 37 additions & 22 deletions docker/build_scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,10 @@ 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"
PYTHON_COMPILE_DEPS="zlib-devel bzip2-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 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
# Libraries that are allowed as part of the manylinux2010 profile
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
Expand All @@ -43,16 +33,17 @@ 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
# https://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
cp $MY_DIR/epel-release-6-8.noarch.rpm .
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should be concerned about this, but note that this doesnot correspond to centos 6.10. I'm not sure what the canonical location for the extended package for enterpriselinux (EPEL) rpm is, myself.

check_sha256sum epel-release-6-8.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
rpm -Uvh --replacepkgs epel-release-6*.rpm
rm -f epel-release-6*.rpm


# Development tools and libraries
yum -y install \
Expand All @@ -67,10 +58,12 @@ yum -y install \
diffutils \
expat-devel \
gettext \
kernel-devel-`uname -r` \
file \
kernel-devel-`uname -r` \
libffi-devel \
make \
patch \
perl-devel \
unzip \
which \
yasm \
Expand Down Expand Up @@ -144,18 +137,40 @@ 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 \
expat-devel \
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

Expand All @@ -177,7 +192,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
Expand Down
2 changes: 1 addition & 1 deletion docker/build_scripts/build_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ GIT_HASH=46f3a29c250313276ac747a3a221ca69dbc3218754f8db188841322cf7ab58d3
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
5 changes: 1 addition & 4 deletions docker/build_scripts/build_utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Binary file removed docker/build_scripts/epel-release-5-4.noarch.rpm
Binary file not shown.
Binary file added docker/build_scripts/epel-release-6-8.noarch.rpm
Binary file not shown.
50 changes: 50 additions & 0 deletions docker/build_scripts/linux32
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/python
"""
Emulate linux32, i.e. setarch(8).
"""
import os
import ctypes
import sys

# Retrieved from a 32-bit CentOS 6.9 installation's
# /usr/include/sys/personality.h header.
LINUX_32 = 0x0008

# Grab libc from our process
process_namespace = ctypes.CDLL(None, use_errno=True)
# int personality(unsigned long persona);
__syscall_personality = process_namespace.personality
__syscall_personality.argtypes = [ctypes.c_ulong]
__syscall_personality.restype = ctypes.c_int


def personality(persona):
"""
Wrap behavior of personality(2).
"""
set_persona = __syscall_personality(persona)
if set_persona == -1:
errno = ctypes.get_errno()
OSError(errno, os.strerror(errno))

return set_persona


personality(LINUX_32)

argv = sys.argv[1:]
if not argv:
os.execlp("/bin/sh", "-sh")
elif argv[0] in ('-h', '--h', '-help', '--help'):
print("""Usage:
linux32 [<program> [<argument>...]]

Change the reported architecture to 32 bits.
THIS IS JUST A STUB FOR BOOTSTRAPPING!
Please install utils-linux-ng for the real executable.
""")
elif argv[0].startswith('-'):
print("linux32: Unknown option")
print("linux32: Try `linux32 --help' for more information.")
else:
os.execvp(argv[0], argv)
Original file line number Diff line number Diff line change
@@ -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"]:
Expand All @@ -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
Expand Down Expand Up @@ -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)
2 changes: 1 addition & 1 deletion docker/deploy.sh
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions docker/glibc/Dockerfile
Original file line number Diff line number Diff line change
@@ -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
79 changes: 79 additions & 0 deletions docker/glibc/README.rst
Original file line number Diff line number Diff line change
@@ -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 ``manylinux2`` on 64-bit
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

manylinux2 -> manylinux2010

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
``manylinux2`` 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 manylinux2'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
7 changes: 7 additions & 0 deletions docker/glibc/build_scripts/CentOS-source.repo
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[base-source]
name=CentOS-6.10 - Base SRPMS
baseurl=http://vault.centos.org/6.10/os/Source/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6
priority=1
enabled=1
Loading