Home | History | Annotate | Download | only in image_signing
      1 #!/bin/bash
      2 
      3 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 # Abort on error.
      8 set -e
      9 
     10 LSB_FILE=/etc/lsb-release
     11 
     12 # Load common constants and variables.
     13 . "$(dirname "$0")/common.sh"
     14 
     15 usage() {
     16   echo "Usage $PROG image [config]"
     17 }
     18 
     19 # Usage: lsbval path-to-lsb-file key
     20 # Returns the value for the given lsb-release file variable.
     21 lsbval() {
     22   local lsbfile="$1"
     23   local key="$2"
     24   grep ^$key= "$lsbfile" | sed s/^$key=//
     25 }
     26 
     27 # Usage: lsbequals path-to-lsb-file key expected-value
     28 # Returns 0 if they match, 1 otherwise.
     29 # Also outputs a warning message if they don't match.
     30 lsbequals() {
     31   local lsbfile="$1"
     32   local key="$2"
     33   local expectval="$3"
     34   local realval=$(lsbval "$lsbfile" $key)
     35   if [ "$realval" != "$expectval" ]; then
     36     echo "$key mismatch. Expected '$expectval', image contains '$realval'"
     37     return 1
     38   fi
     39   return 0
     40 }
     41 
     42 # Usage: check_keyval_in_list lsbfile lsbkey [list of values]
     43 # Extracts the lsb-release value for the specified key, and confirms it
     44 # matches one of the whitelisted values specified in value_array.
     45 # Implementation note:
     46 # You can't really pass bash arrays to functions. Best you can do is either
     47 # serialize to string/pass/deserialize (e.g. using whitspace/IFS hacks), or,
     48 # let the array contents be received as multiple arguments to the target
     49 # function. We take the latter approach here, hence the shift's to get the
     50 # first 2 arguments out, before we process the rest of the varargs.
     51 check_keyval_in_list() {
     52   local lsbfile="$1"
     53   shift
     54   local lsbkey="$1"
     55   shift
     56   local lsbval=$(lsbval "$lsbfile" "$lsbkey")
     57   while [ $# -gt 0 ]; do
     58     if [ "$lsbval" == "$1" ]; then
     59       return 0
     60     fi
     61     shift
     62   done
     63   # If we get here, it wasn't found
     64   echo "$lsbkey: Value '$lsbval' was not recognized"
     65   return 1
     66 }
     67 
     68 # Usage: lsb_syntaxcheck path-to-lsb-file
     69 # Enforces a number of basic sanity checks on the overall format and contents
     70 # of the lsb-release file:
     71 # - Every line is "key=value".
     72 # - No space after key, no space before value.
     73 # - key is all A-Z or _, but not starting with _.
     74 # - value is made up of printable characters, or is empty.
     75 # - Each line is a reasonable size (<255 bytes).
     76 # - The whole file is a reasonable size (4kb).
     77 lsb_syntaxcheck() {
     78   local lsbfile="$1"
     79   syntaxbad=0
     80   # Checks for key being A-Z_, 1 or more characters, not starting with _.
     81   # Also checks for = with no spaces on either side.
     82   # Checks that the value contains printables (and not starting with space).
     83   # Alternatively, the value is permitted to be empty (0 chars) too.
     84   badlines=$(grep -Ev '^[A-Z][A-Z_]*=([[:graph:]][[:print:]]*)?$' "$lsbfile")
     85   if [ -n "$badlines" ]; then
     86     syntaxbad=1
     87     echo "$lsbfile: Some lines seem non-well-formed:"
     88     echo "$badlines"
     89   fi
     90 
     91   # Checks for a lines exceeding a reasonable overall length.
     92   badlines=$(grep -E '^.{255}' "$lsbfile")
     93   if [ -n "$badlines" ]; then
     94     syntaxbad=1
     95     echo "$lsbfile: Some lsb-release lines seem unreasonably long:"
     96     echo "$badlines"
     97   fi
     98   # Overall file size check:
     99   size=$(ls -sk "$lsbfile" | cut -d ' ' -f 1)
    100   if [ $size -gt 4 ]; then
    101     syntaxbad=1
    102     echo "$lsbfile: This file exceeds 4kb"
    103   fi
    104   return $syntaxbad
    105 }
    106 
    107 main() {
    108   # We want to catch all the discrepancies, not just the first one.
    109   # So, any time we find one, we set testfail=1 and continue.
    110   # When finished we will use testfail to determine our exit value.
    111   local testfail=0
    112 
    113   if [ $# -ne 1 ] && [ $# -ne 2 ]; then
    114     usage
    115     exit 1
    116   fi
    117 
    118   local image="$1"
    119 
    120   # Default config location: same directory as this script.
    121   local configfile="$(dirname "$0")/default_lsb_release.config"
    122   # Or, maybe a config was provided on the command line.
    123   if [ $# -eq 2 ]; then
    124     configfile="$2"
    125   fi
    126   # Either way, load test-expectations data from config.
    127   echo -n "Loading config from $configfile... "
    128   . "$configfile" || return 1
    129   echo "Done."
    130 
    131   local rootfs=$(make_temp_dir)
    132   mount_image_partition_ro "$image" 3 "$rootfs"
    133   local lsb="$rootfs/$LSB_FILE"
    134 
    135   # Basic syntax check first.
    136   lsb_syntaxcheck "$lsb" || testfail=1
    137 
    138   lsbequals $lsb CHROMEOS_AUSERVER "$expected_auserver" || testfail=1
    139   lsbequals $lsb CHROMEOS_RELEASE_NAME "$expected_release_name" || testfail=1
    140   check_keyval_in_list $lsb CHROMEOS_RELEASE_TRACK \
    141     "${expected_release_tracks[@]}" || testfail=1
    142 
    143   if check_keyval_in_list $lsb CHROMEOS_RELEASE_BOARD \
    144     "${expected_boards[@]}"; then
    145     # Pick the right set of test-expectation data to use. The cuts
    146     # turn e.g. x86-foo-pvtkeys into x86-foo.
    147     local board=$(lsbval $lsb CHROMEOS_RELEASE_BOARD |
    148                   cut -d = -f 2 |
    149                   cut -d - -f 1,2)
    150     # a copy of the board string with '-' squished to variable-name-safe '_'.
    151     local boardvar=${board//-/_}
    152     channel=$(lsbval $lsb CHROMEOS_RELEASE_TRACK)
    153     # For a canary or dogfood channel, appid maybe a different default value.
    154     if [ $channel = 'canary-channel' ] || [ $channel = 'dogfood-channel' ]; then
    155       eval "expected_appid=\"\$expected_appid_${channel%\-channel}\""
    156     else
    157       eval "expected_appid=\"\$expected_appid_$boardvar\""
    158     fi
    159     lsbequals $lsb CHROMEOS_RELEASE_APPID "$expected_appid" || testfail=1
    160   else # unrecognized board
    161     testfail=1
    162   fi
    163 
    164   exit $testfail
    165 }
    166 
    167 main "$@"
    168