There is a long-standing
[bug report](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61439)
pointing out that the `download_prerequisites` script doesn't verify the
integrity of the packages it downloads.  The original bug report is only
concerned about stability but for me, this is first and foremost a
security issue.  Even more so since the downloads happen over unsecured
FTP connections.

I have already posted an improved version of the script that does verify
checksums on the Bugzilla thread in February this year but apparently,
it went unnoticed there.

Coincidentally, another person posted an alternative solution at the
same place just about the same time that didn't seem to have received
any attention either.  Their fix is minimal invasive while I essentially
re-wrote the script and added a bunch of command-line options.  I
believe those are useful but you could also arguably call it
over-engineering.  I'm okay with either fix but I'm not going to speak
for the other person so I'll only explain my own patch here.

The script relies on the files `contrib/prerequisites.sha512` and
`contrib/prerequisites.md5` to be present in the GCC tarball and will
use them to verify the package integrity.  Said files are tiny and
readily available here

    ftp://gcc.gnu.org/pub/gcc/infrastructure/sha512.sum
    ftp://gcc.gnu.org/pub/gcc/infrastructure/md5.sum

but I didn't include them into the patch because I have no way of
verifying their integrity.  Somebody who has secure access to the GNU
servers should verify that we add the correct checksums into the GCC
archive.  Every time a new version of the prerequisites is used, the
checksum files have to be updated as well.

The integrity of the downloaded prerequisites then follows transitively
assuming that GCC's own tarball hasn't been tampered with which we have
to assume anyway.  (Ensuring this is beyond the scope of anything we can
put *inside* the tarball itself.)

Since my patch doesn't contain said checksum files and other than that,
merely replaces a single file completely, I'm attaching just the new
version of the `download_prerequisites` scripts and not a diff.  It
would be nice of somebody with trusted access to the GNU servers could
be so kind to prepare the actual SVN patch for me.

After adding the checksum files, the ChangeLog entry might be like this:

        * contrib/download_prerequisites: Verify integrity of downloaded
        packages and added more command-line options.

        * contrib/prerequisites.sha512: New.

        * contrib/prerequisites.md5: New.

I already went through the copyright assignment process for GCC so I
think you should be able to include my patch if it is accepted.  (I also
took the liberty to mention the FSF as copyright holder in the script
without waiting for the patch being accepted.)

I believe that attacking a system by compromising the compiler is a very
serious threat so I hope that you'll consider patching the script.  If
there are any portability or other issues with the way I wrote the
script, I'll be ready to fix them.


Moritz
-- 
OpenPGP:

Public Key:   http://openpgp.klammler.eu
Fingerprint:  2732 DA32 C8D0 EEEC A081  BE9D CF6C 5166 F393 A9C0

#! /bin/sh -eu
#! -*- coding:utf-8; mode:shell-script; -*-

# Download some prerequisites needed by GCC.
# Run this from the top level of the Gcc source tree and the Gcc build will do
# the right thing.  Run it with the `--help` option for more information.
#
# (C) 2016 Free Software Foundation
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see http://www.gnu.org/licenses/.


program='download_prerequisites'
version='(unversioned)'

graphite=1
verify=1
force=0
chksum='sha512'
directory='.'

gmp='gmp-4.3.2.tar.bz2'
mpfr='mpfr-2.4.2.tar.bz2'
mpc='mpc-0.8.1.tar.gz'
isl='isl-0.15.tar.bz2'

base_url='ftp://gcc.gnu.org/pub/gcc/infrastructure/'

echo_archives() {
    echo "${gmp}"
    echo "${mpfr}"
    echo "${mpc}"
    if [ ${graphite} -gt 0 ]; then echo "${isl}"; fi
}

helptext="usage: ${program} [OPTION...]

Downloads some prerequisites needed by GCC.  Run this from the top level of the
GCC source tree and the GCC build will do the right thing.

The following options are available:

 --directory=DIR  download and unpack packages into DIR instead of '.'
 --force          download again overwriting existing packages
 --no-force       do not download existing packages again (default)
 --isl            download ISL, needed for Graphite loop optimizations (default)
 --graphite       same as --isl
 --no-isl         don't download ISL
 --no-graphite    same as --no-isl
 --verify         verify package integrity after download (default)
 --no-verify      don't verify package integrity
 --sha512         use SHA512 checksum to verify package integrity (default)
 --md5            use MD5 checksum to verify package integrity
 --help           show this text and exit
 --version        show version information and exit
"

versiontext="${program} ${version}
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

die() {
    echo "error: $@" >&2
    exit 1
}

for arg in "$@"
do
    case "${arg}" in
        --help)
            echo "${helptext}"
            exit
            ;;
        --version)
            echo "${versiontext}"
            exit
            ;;
    esac
done
unset arg

argnext=
for arg in "$@"
do
    if [ "x${argnext}" = x ]
    then
        case "${arg}" in
            --directory)
                argnext='directory'
                ;;
            --directory=*)
                directory="${arg#--directory=}"
                ;;
            --force)
                force=1
                ;;
            --no-force)
                force=0
                ;;
            --isl|--graphite)
                graphite=1
                ;;
            --no-isl|--no-graphite)
                graphite=0
                ;;
            --verify)
                verify=1
                ;;
            --no-verify)
                verify=0
                ;;
            --sha512)
                chksum='sha512'
                verify=1
                ;;
            --md5)
                chksum='md5'
                verify=1
                ;;
            -*)
                die "unknown option: ${arg}"
                ;;
            *)
                die "too many arguments"
                ;;
        esac
    else
        case "${arg}" in
            -*)
                die "Missing argument for option --${argnext}"
                ;;
        esac
        case "${argnext}" in
            directory)
                directory="${arg}"
                ;;
            *)
                die "The impossible has happened"
                ;;
        esac
        argnext=
    fi
done
[ "x${argnext}" = x ] || die "Missing argument for option --${argnext}"
unset arg argnext

[ -e ./gcc/BASE-VER ]                                                         \
    || die "You must run this script in the top-level GCC source directory"

[ -d "${directory}" ]                                                         \
    || die "No such directory: ${directory}"

for ar in $(echo_archives)
do
    if [ ${force} -gt 0 ]; then rm -f "${directory}/${ar}"; fi
    [ -e "${directory}/${ar}" ]                                               \
        || wget --no-verbose -O "${directory}/${ar}" "${base_url}${ar}"       \
        || die "Cannot download ${ar} from ${base_url}"
done
unset ar

if [ ${verify} -gt 0 ]
then
    chksumfile="contrib/prerequisites.${chksum}"
    [ -r "${chksumfile}" ] || die "No checksums available"
    for ar in $(echo_archives)
    do
        grep "${ar}" "${chksumfile}"                                          \
            | ( cd "${directory}" && "${chksum}sum" --check )                 \
            || die "Cannot verify integrity of possibly corrupted file ${ar}"
    done
    unset chksumfile
fi
unset ar

for ar in $(echo_archives)
do
    package="${ar%.tar*}"
    if [ ${force} -gt 0 ]; then rm -rf "${directory}/${package}"; fi
    [ -e "${directory}/${package}" ]                                          \
        || ( cd "${directory}" && tar -xf "${ar}" )                           \
        || die "Cannot extract package from ${ar}"
    unset package
done
unset ar

for ar in $(echo_archives)
do
    target="${directory}/${ar%.tar*}/"
    linkname="${ar%-*}"
    if [ ${force} -gt 0 ]; then rm -f "${linkname}"; fi
    [ -e "${linkname}" ]                                                      \
        || ln -s "${target}" "${linkname}"                                    \
        || die "Cannot create symbolic link ${linkname} --> ${target}"
    unset target linkname
done
unset ar

echo "All prerequisites downloaded successfully."

Attachment: signature.asc
Description: PGP signature

Reply via email to