pkg-download: verify the hashes from the download wrapper

Instead of repeating the check in our download rules, delegate the check
of the hashes to the download wrapper.

This needs three different changes:

  - add a new argument to the download wrapper, that is the full path to
    the hash file; if the hash file does not exist, that does not change
    the current behaviour, as the existence of the hash file is checked
    for in the check-hash script;

  - add a third argument to the check-hash script, to be the basename of
    the file to check; this is required because we no longer check the
    final file with the final filename, but an intermediate file with a
    temporary filename;

  - do the actual call to the check-hash script from within the download
    wrapper.

This further paves the way to doing pre-download checks of the hashes
for the locally cached files.

Note: this patch removes the check for hashes for already downloaded
files, since the wrapper script exits early. The behaviour to check
localy cached files will be restored and enhanced in the following
patch.

[Thomas: fix minor typo in comment.]

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Peter Korsgaard <jacmet@uclibc.org>
Cc: Gustavo Zacarias <gustavo@zacarias.com.ar>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
This commit is contained in:
Yann E. MORIN 2014-12-11 23:52:07 +01:00 committed by Thomas Petazzoni
parent 2685937e06
commit 9b88c60484
3 changed files with 40 additions and 26 deletions

View File

@ -60,17 +60,6 @@ domainseparator = $(if $(1),$(1),/)
# github(user,package,version): returns site of GitHub repository # github(user,package,version): returns site of GitHub repository
github = https://github.com/$(1)/$(2)/archive/$(3) github = https://github.com/$(1)/$(2)/archive/$(3)
# Helper for checking a tarball's checksum
# If the hash does not match, remove the incorrect file
# $(1): the path to the file with the hashes
# $(2): the full path to the file to check
define VERIFY_HASH
if ! support/download/check-hash $(1) $(2) $(if $(QUIET),>/dev/null); then \
rm -f $(2); \
exit 1; \
fi
endef
################################################################################ ################################################################################
# The DOWNLOAD_* helpers are in charge of getting a working copy # The DOWNLOAD_* helpers are in charge of getting a working copy
# of the source repository for their corresponding SCM, # of the source repository for their corresponding SCM,
@ -98,6 +87,7 @@ endef
define DOWNLOAD_GIT define DOWNLOAD_GIT
$(EXTRA_ENV) $(DL_WRAPPER) -b git \ $(EXTRA_ENV) $(DL_WRAPPER) -b git \
-o $(DL_DIR)/$($(PKG)_SOURCE) \ -o $(DL_DIR)/$($(PKG)_SOURCE) \
-H $(PKGDIR)/$($(PKG)_RAWNAME).hash \
-- \ -- \
$($(PKG)_SITE) \ $($(PKG)_SITE) \
$($(PKG)_DL_VERSION) \ $($(PKG)_DL_VERSION) \
@ -118,6 +108,7 @@ endef
define DOWNLOAD_BZR define DOWNLOAD_BZR
$(EXTRA_ENV) $(DL_WRAPPER) -b bzr \ $(EXTRA_ENV) $(DL_WRAPPER) -b bzr \
-o $(DL_DIR)/$($(PKG)_SOURCE) \ -o $(DL_DIR)/$($(PKG)_SOURCE) \
-H $(PKGDIR)/$($(PKG)_RAWNAME).hash \
-- \ -- \
$($(PKG)_SITE) \ $($(PKG)_SITE) \
$($(PKG)_DL_VERSION) \ $($(PKG)_DL_VERSION) \
@ -135,6 +126,7 @@ endef
define DOWNLOAD_CVS define DOWNLOAD_CVS
$(EXTRA_ENV) $(DL_WRAPPER) -b cvs \ $(EXTRA_ENV) $(DL_WRAPPER) -b cvs \
-o $(DL_DIR)/$($(PKG)_SOURCE) \ -o $(DL_DIR)/$($(PKG)_SOURCE) \
-H $(PKGDIR)/$($(PKG)_RAWNAME).hash \
-- \ -- \
$(call stripurischeme,$(call qstrip,$($(PKG)_SITE))) \ $(call stripurischeme,$(call qstrip,$($(PKG)_SITE))) \
$($(PKG)_DL_VERSION) \ $($(PKG)_DL_VERSION) \
@ -154,6 +146,7 @@ endef
define DOWNLOAD_SVN define DOWNLOAD_SVN
$(EXTRA_ENV) $(DL_WRAPPER) -b svn \ $(EXTRA_ENV) $(DL_WRAPPER) -b svn \
-o $(DL_DIR)/$($(PKG)_SOURCE) \ -o $(DL_DIR)/$($(PKG)_SOURCE) \
-H $(PKGDIR)/$($(PKG)_RAWNAME).hash \
-- \ -- \
$($(PKG)_SITE) \ $($(PKG)_SITE) \
$($(PKG)_DL_VERSION) \ $($(PKG)_DL_VERSION) \
@ -174,9 +167,9 @@ endef
define DOWNLOAD_SCP define DOWNLOAD_SCP
$(EXTRA_ENV) $(DL_WRAPPER) -b scp \ $(EXTRA_ENV) $(DL_WRAPPER) -b scp \
-o $(DL_DIR)/$(2) \ -o $(DL_DIR)/$(2) \
-H $(PKGDIR)/$($(PKG)_RAWNAME).hash \
-- \ -- \
'$(call stripurischeme,$(call qstrip,$(1)))' && \ '$(call stripurischeme,$(call qstrip,$(1)))'
$(call VERIFY_HASH,$(PKGDIR)/$($(PKG)_RAWNAME).hash,$(DL_DIR)/$(2))
endef endef
define SOURCE_CHECK_SCP define SOURCE_CHECK_SCP
@ -191,6 +184,7 @@ endef
define DOWNLOAD_HG define DOWNLOAD_HG
$(EXTRA_ENV) $(DL_WRAPPER) -b hg \ $(EXTRA_ENV) $(DL_WRAPPER) -b hg \
-o $(DL_DIR)/$($(PKG)_SOURCE) \ -o $(DL_DIR)/$($(PKG)_SOURCE) \
-H $(PKGDIR)/$($(PKG)_RAWNAME).hash \
-- \ -- \
$($(PKG)_SITE) \ $($(PKG)_SITE) \
$($(PKG)_DL_VERSION) \ $($(PKG)_DL_VERSION) \
@ -211,9 +205,9 @@ endef
define DOWNLOAD_WGET define DOWNLOAD_WGET
$(EXTRA_ENV) $(DL_WRAPPER) -b wget \ $(EXTRA_ENV) $(DL_WRAPPER) -b wget \
-o $(DL_DIR)/$(2) \ -o $(DL_DIR)/$(2) \
-H $(PKGDIR)/$($(PKG)_RAWNAME).hash \
-- \ -- \
'$(call qstrip,$(1))' && \ '$(call qstrip,$(1))'
$(call VERIFY_HASH,$(PKGDIR)/$($(PKG)_RAWNAME).hash,$(DL_DIR)/$(2))
endef endef
define SOURCE_CHECK_WGET define SOURCE_CHECK_WGET
@ -227,9 +221,9 @@ endef
define DOWNLOAD_LOCALFILES define DOWNLOAD_LOCALFILES
$(EXTRA_ENV) $(DL_WRAPPER) -b cp \ $(EXTRA_ENV) $(DL_WRAPPER) -b cp \
-o $(DL_DIR)/$(2) \ -o $(DL_DIR)/$(2) \
-H $(PKGDIR)/$($(PKG)_RAWNAME).hash \
-- \ -- \
$(call stripurischeme,$(call qstrip,$(1))) && \ $(call stripurischeme,$(call qstrip,$(1)))
$(call VERIFY_HASH,$(PKGDIR)/$($(PKG)_RAWNAME).hash,$(DL_DIR)/$(2))
endef endef
define SOURCE_CHECK_LOCALFILES define SOURCE_CHECK_LOCALFILES

View File

@ -4,10 +4,15 @@ set -e
# Helper to check a file matches its known hash # Helper to check a file matches its known hash
# Call it with: # Call it with:
# $1: the path of the file containing all the the expected hashes # $1: the path of the file containing all the the expected hashes
# $2: the full path to the file to check # $2: the full path to the temporary file that was downloaded, and
# that is to be checked
# $3: the final basename of the file, to which it will be ultimately
# saved as, to be able to match it to the corresponding hashes
# in the .hash file
h_file="${1}" h_file="${1}"
file="${2}" file="${2}"
base="${3}"
# Does the hash-file exist? # Does the hash-file exist?
if [ ! -f "${h_file}" ]; then if [ ! -f "${h_file}" ]; then
@ -30,7 +35,7 @@ check_one_hash() {
sha224|sha256|sha384|sha512) ;; sha224|sha256|sha384|sha512) ;;
*) # Unknown hash, exit with error *) # Unknown hash, exit with error
printf "ERROR: unknown hash '%s' for '%s'\n" \ printf "ERROR: unknown hash '%s' for '%s'\n" \
"${_h}" "${_file##*/}" >&2 "${_h}" "${base}" >&2
exit 1 exit 1
;; ;;
esac esac
@ -38,11 +43,11 @@ check_one_hash() {
# Do the hashes match? # Do the hashes match?
_hash=$( ${_h}sum "${_file}" |cut -d ' ' -f 1 ) _hash=$( ${_h}sum "${_file}" |cut -d ' ' -f 1 )
if [ "${_hash}" = "${_known}" ]; then if [ "${_hash}" = "${_known}" ]; then
printf "%s: OK (%s: %s)\n" "${_file##*/}" "${_h}" "${_hash}" printf "%s: OK (%s: %s)\n" "${base}" "${_h}" "${_hash}"
return 0 return 0
fi fi
printf "ERROR: %s has wrong %s hash:\n" "${_file##*/}" "${_h}" >&2 printf "ERROR: %s has wrong %s hash:\n" "${base}" "${_h}" >&2
printf "ERROR: expected: %s\n" "${_known}" >&2 printf "ERROR: expected: %s\n" "${_known}" >&2
printf "ERROR: got : %s\n" "${_hash}" >&2 printf "ERROR: got : %s\n" "${_hash}" >&2
printf "ERROR: Incomplete download, or man-in-the-middle (MITM) attack\n" >&2 printf "ERROR: Incomplete download, or man-in-the-middle (MITM) attack\n" >&2
@ -59,7 +64,7 @@ while read t h f; do
continue continue
;; ;;
*) *)
if [ "${f}" = "${file##*/}" ]; then if [ "${f}" = "${base}" ]; then
check_one_hash "${t}" "${h}" "${file}" check_one_hash "${t}" "${h}" "${file}"
: $((nb_checks++)) : $((nb_checks++))
fi fi
@ -69,9 +74,9 @@ done <"${h_file}"
if [ ${nb_checks} -eq 0 ]; then if [ ${nb_checks} -eq 0 ]; then
if [ -n "${BR2_ENFORCE_CHECK_HASH}" ]; then if [ -n "${BR2_ENFORCE_CHECK_HASH}" ]; then
printf "ERROR: No hash found for %s\n" "${file}" >&2 printf "ERROR: No hash found for %s\n" "${base}" >&2
exit 1 exit 1
else else
printf "WARNING: No hash found for %s\n" "${file}" >&2 printf "WARNING: No hash found for %s\n" "${base}" >&2
fi fi
fi fi

View File

@ -21,14 +21,15 @@ set -e
main() { main() {
local OPT OPTARG local OPT OPTARG
local backend output local backend output hfile
# Parse our options; anything after '--' is for the backend # Parse our options; anything after '--' is for the backend
while getopts :hb:o: OPT; do while getopts :hb:o:H: OPT; do
case "${OPT}" in case "${OPT}" in
h) help; exit 0;; h) help; exit 0;;
b) backend="${OPTARG}";; b) backend="${OPTARG}";;
o) output="${OPTARG}";; o) output="${OPTARG}";;
H) hfile="${OPTARG}";;
:) error "option '%s' expects a mandatory argument\n" "${OPTARG}";; :) error "option '%s' expects a mandatory argument\n" "${OPTARG}";;
\?) error "unknown option '%s'\n" "${OPTARG}";; \?) error "unknown option '%s'\n" "${OPTARG}";;
esac esac
@ -42,6 +43,9 @@ main() {
if [ -z "${output}" ]; then if [ -z "${output}" ]; then
error "no output specified, use -o\n" error "no output specified, use -o\n"
fi fi
if [ -z "${hfile}" ]; then
error "no hash-file specified, use -H\n"
fi
# If the output file already exists, do not download it again # If the output file already exists, do not download it again
if [ -e "${output}" ]; then if [ -e "${output}" ]; then
@ -75,6 +79,13 @@ main() {
# cd back to free the temp-dir, so we can remove it later # cd back to free the temp-dir, so we can remove it later
cd "${OLDPWD}" cd "${OLDPWD}"
# Check if the downloaded file is sane, and matches the stored hashes
# for that file
if ! support/download/check-hash "${hfile}" "${tmpf}" "${output##*/}"; then
rm -rf "${tmpd}"
exit 1
fi
# tmp_output is in the same directory as the final output, so we can # tmp_output is in the same directory as the final output, so we can
# later move it atomically. # later move it atomically.
tmp_output="$(mktemp "${output}.XXXXXX")" tmp_output="$(mktemp "${output}.XXXXXX")"
@ -150,6 +161,10 @@ DESCRIPTION
-o FILE -o FILE
Store the downloaded archive in FILE. Store the downloaded archive in FILE.
-H FILE
Use FILE to read hashes from, and check them against the downloaded
archive.
Exit status: Exit status:
0 if OK 0 if OK
!0 in case of error !0 in case of error