summaryrefslogtreecommitdiff
path: root/scripts/image_signing/ensure_sane_lsb-release.sh
blob: a5abc3c11ac89ab14e0d151b697dd257800f9935 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/bin/bash

# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Abort on error.
set -e

LSB_FILE=/etc/lsb-release

# Load common constants and variables.
. "$(dirname "$0")/common.sh"

usage() {
  echo "Usage $PROG image [config]"
}

# Usage: lsbval path-to-lsb-file key
# Returns the value for the given lsb-release file variable.
lsbval() {
  local lsbfile="$1"
  local key="$2"
  grep ^$key= "$lsbfile" | sed s/^$key=//
}

# Usage: lsbequals path-to-lsb-file key expected-value
# Returns 0 if they match, 1 otherwise.
# Also outputs a warning message if they don't match.
lsbequals() {
  local lsbfile="$1"
  local key="$2"
  local expectval="$3"
  local realval=$(lsbval "$lsbfile" $key)
  if [ "$realval" != "$expectval" ]; then
    echo "$key mismatch. Expected '$expectval', image contains '$realval'"
    return 1
  fi
  return 0
}

# Usage: check_keyval_in_list lsbfile lsbkey [list of values]
# Extracts the lsb-release value for the specified key, and confirms it
# matches one of the whitelisted values specified in value_array.
# Implementation note:
# You can't really pass bash arrays to functions. Best you can do is either
# serialize to string/pass/deserialize (e.g. using whitspace/IFS hacks), or,
# let the array contents be received as multiple arguments to the target
# function. We take the latter approach here, hence the shift's to get the
# first 2 arguments out, before we process the rest of the varargs.
check_keyval_in_list() {
  local lsbfile="$1"
  shift
  local lsbkey="$1"
  shift
  local lsbval=$(lsbval "$lsbfile" "$lsbkey")
  while [ $# -gt 0 ]; do
    if [ "$lsbval" == "$1" ]; then
      return 0
    fi
    shift
  done
  # If we get here, it wasn't found
  echo "$lsbkey: Value '$lsbval' was not recognized"
  return 1
}

# Usage: lsb_syntaxcheck path-to-lsb-file
# Enforces a number of basic sanity checks on the overall format and contents
# of the lsb-release file:
# - Every line is "key=value".
# - No space after key, no space before value.
# - key is all A-Z or _, but not starting with _.
# - value is made up of printable characters, or is empty.
# - Each line is a reasonable size (<255 bytes).
# - The whole file is a reasonable size (4kb).
lsb_syntaxcheck() {
  local lsbfile="$1"
  syntaxbad=0
  # Checks for key being A-Z_, 1 or more characters, not starting with _.
  # Also checks for = with no spaces on either side.
  # Checks that the value contains printables (and not starting with space).
  # Alternatively, the value is permitted to be empty (0 chars) too.
  badlines=$(grep -Ev '^[A-Z][A-Z_]*=([[:graph:]][[:print:]]*)?$' "$lsbfile")
  if [ -n "$badlines" ]; then
    syntaxbad=1
    echo "$lsbfile: Some lines seem non-well-formed:"
    echo "$badlines"
  fi

  # Checks for a lines exceeding a reasonable overall length.
  badlines=$(grep -E '^.{255}' "$lsbfile")
  if [ -n "$badlines" ]; then
    syntaxbad=1
    echo "$lsbfile: Some lsb-release lines seem unreasonably long:"
    echo "$badlines"
  fi
  # Overall file size check:
  size=$(ls -sk "$lsbfile" | cut -d ' ' -f 1)
  if [ $size -gt 4 ]; then
    syntaxbad=1
    echo "$lsbfile: This file exceeds 4kb"
  fi
  return $syntaxbad
}

main() {
  # We want to catch all the discrepancies, not just the first one.
  # So, any time we find one, we set testfail=1 and continue.
  # When finished we will use testfail to determine our exit value.
  local testfail=0

  if [ $# -ne 1 ] && [ $# -ne 2 ]; then
    usage
    exit 1
  fi

  local image="$1"

  # Default config location: same directory as this script.
  local configfile="$(dirname "$0")/default_lsb_release.config"
  # Or, maybe a config was provided on the command line.
  if [ $# -eq 2 ]; then
    configfile="$2"
  fi
  # Either way, load test-expectations data from config.
  echo -n "Loading config from $configfile... "
  . "$configfile" || return 1
  echo "Done."

  local rootfs=$(make_temp_dir)
  mount_image_partition_ro "$image" 3 "$rootfs"
  local lsb="$rootfs/$LSB_FILE"

  # Basic syntax check first.
  lsb_syntaxcheck "$lsb" || testfail=1

  lsbequals $lsb CHROMEOS_AUSERVER "$expected_auserver" || testfail=1
  lsbequals $lsb CHROMEOS_RELEASE_NAME "$expected_release_name" || testfail=1
  check_keyval_in_list $lsb CHROMEOS_RELEASE_TRACK \
    "${expected_release_tracks[@]}" || testfail=1

  if check_keyval_in_list $lsb CHROMEOS_RELEASE_BOARD \
    "${expected_boards[@]}"; then
    # Pick the right set of test-expectation data to use. The cuts
    # turn e.g. x86-foo-pvtkeys into x86-foo.
    local board=$(lsbval $lsb CHROMEOS_RELEASE_BOARD |
                  cut -d = -f 2 |
                  cut -d - -f 1,2)
    # a copy of the board string with '-' squished to variable-name-safe '_'.
    local boardvar=${board//-/_}
    channel=$(lsbval $lsb CHROMEOS_RELEASE_TRACK)
    # For a canary or dogfood channel, appid maybe a different default value.
    if [ $channel = 'canary-channel' ] || [ $channel = 'dogfood-channel' ]; then
      eval "expected_appid=\"\$expected_appid_${channel%\-channel}\""
    else
      eval "expected_appid=\"\$expected_appid_$boardvar\""
    fi
    lsbequals $lsb CHROMEOS_RELEASE_APPID "$expected_appid" || testfail=1
  else # unrecognized board
    testfail=1
  fi

  exit $testfail
}

main "$@"