]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
UBUNTU: [Packaging] retpoline -- add safe usage hint support
authorAndy Whitcroft <apw@canonical.com>
Thu, 8 Mar 2018 15:48:31 +0000 (15:48 +0000)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Thu, 5 Apr 2018 08:41:57 +0000 (10:41 +0200)
BugLink: http://bugs.launchpad.net/bugs/1758856
Use the upstream retpoline safe hinting support to clear out known
safe retpoline sequences from those detected.  At the same time
switch to extracting the indirect sequences and associated hints
to .o generation time.  This allows it to be run on the cache hot
data and to be run in parallel on the builders.

Signed-off-by: Andy Whitcroft <apw@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
debian/rules.d/4-checks.mk
debian/scripts/retpoline-extract
debian/scripts/retpoline-extract-one [new file with mode: 0755]
scripts/Makefile.build

index 108c80ecfe5908a5418cf76cc0726ea368893854..52e5a68fe95c95d75c82b3a7b7e6a6e45695b8de 100644 (file)
@@ -21,13 +21,13 @@ retpoline-check-%: $(stampdir)/stamp-build-%
        @echo Debug: $@
        install -d $(abidir)
        if grep -q CONFIG_RETPOLINE=y $(builddir)/build-$*/.config; then \
-               $(SHELL) $(DROOT)/scripts/retpoline-extract $(builddir)/build-$* | \
+               $(SHELL) $(DROOT)/scripts/retpoline-extract $(builddir)/build-$* $(CURDIR) | \
                        sort >$(abidir)/$*.retpoline; \
        else \
                echo "# RETPOLINE NOT ENABLED" >$(abidir)/$*.retpoline; \
        fi
        $(SHELL) $(DROOT)/scripts/retpoline-check "$*" \
-               "$(prev_abidir)" "$(abidir)" "$(skipretpoline)"
+               "$(prev_abidir)" "$(abidir)" "$(skipretpoline)" "$(builddir)/build-$*"
 
 checks-%: module-check-% abi-check-% retpoline-check-%
        @echo Debug: $@
index 83cbc9e502115f57f8fa7d925b5a8808a54f2acb..53d81847c7f4d3073a0d42b037c99f1573c3cd41 100755 (executable)
@@ -2,13 +2,20 @@
 
 cd "$1" || exit 1
 
-{
-       echo "./vmlinux"
-       find . -name \*.ko
-} | xargs objdump --disassemble | \
-awk -F'        ' '
-       /^.\//                          { file=$1; sub(":.*", "", file); sub("^.*/", "", file); }
-       /^[0-9a-f][0-9a-f]* <.*>:/      { tag=$1; sub(".*<", "", tag); sub(">.*", "", tag); tag=file " " tag; }
-       $3 ~ /(call|jmp)q?  *\*(0x[a-f0-9]+\()?%/       { print(tag " " $3); }
-' | \
-       grep -v " \*%cs:0x"             # elide 32bit code-segment absolute offsets.
+# Find all valid retpoline information, collate the detected and
+# safe information together.  Join the result to find the detected
+# but non-safe elements.  These are our concern.
+tmp="/tmp/retpoline-check.$$"
+find "." -path './drivers/firmware/efi/libstub' -prune -o \
+        -path './arch/x86/boot' -prune -o \
+        -path './arch/x86/purgatory' -prune -o \
+        -name \*.ur-detected | xargs cat | \
+       sed -e "s@^$1@@" -e "s@ $2/@ @" -e "s@^/@@" | \
+       sort -k 1b,1 >"$tmp.ur-detected"
+find "." -name \*.ur-safe | xargs cat | \
+       sed -e "s@^$1@@" -e "s@^/@@" | \
+       sort -k 1b,1 >"$tmp.ur-safe"
+
+join -v 1 -j 1 "$tmp.ur-detected" "$tmp.ur-safe" | sed -s 's/[^ ]*  *//'
+
+rm -f "$tmp".*
diff --git a/debian/scripts/retpoline-extract-one b/debian/scripts/retpoline-extract-one
new file mode 100755 (executable)
index 0000000..daf877e
--- /dev/null
@@ -0,0 +1,255 @@
+#!/bin/bash
+
+exec </dev/null
+
+object="$1"
+src="$2"
+bit16="$3"
+
+SECTION=".discard.retpoline_safe"
+
+# Form an associative lookup for the symbol numbers in the ELF symbol table.
+# Uses 8 character 0 expanded hexadecimal key for ease of consumption.
+__symbolmap_init()
+{
+       readelf -W --syms "$1" |
+               awk '($4 == "SECTION" && $1 ~ /^[0-9]*:/) { printf("%08x %08x\n", int($1), int($7)); }' | \
+       while read symbol_num section_num
+       do
+               echo "symbolmap_$symbol_num='$section_num'"
+       done
+}
+symbolmap_init()
+{
+       eval $(__symbolmap_init "$1")
+}
+symbolmap()
+{
+       eval RET="\$symbolmap_$1"
+       if [ "$RET" = '' ]; then
+               echo "symbolmap: $1: invalid section" 1>&2
+               exit 1
+       fi
+}
+
+# Form an associative lookup for the section numbers in the ELF symbol table.
+# Uses 8 character 0 expanded hexadecimal key for ease of consumption.
+__sectionmap_init()
+{
+       readelf -W --headers "$1" | \
+               awk '
+                                               { sub("\\[", ""); sub("\\]", ""); }
+                        ($1 ~ /^[0-9][0-9]*/)   { printf("%08x %s %s %s\n", int($1), $2, $3, $4); }
+               ' | \
+       {
+               while read section_num section_name section_type section_vma
+               do
+                       echo "sectionmap_$section_num='$section_name'"
+                       echo "sectionvma_$section_num='$section_vma'"
+                       case "$section_type" in
+                       REL|RELA) section_relocation="$section_type" ;;
+                       esac
+               done
+               echo "section_relocation='$section_relocation'"
+       }
+}
+sectionmap_init()
+{
+       eval $(__sectionmap_init "$1")
+}
+sectionmap()
+{
+       eval RET="\$sectionmap_$1"
+       if [ "$RET" = '' ]; then
+               echo "sectionmap: $1: invalid section" 1>&2
+               exit 1
+       fi
+}
+sectionvma()
+{
+       eval RET="\$sectionvma_$1"
+       if [ "$RET" = '' ]; then
+               echo "sectionvma: $1: invalid section" 1>&2
+               exit 1
+       fi
+}
+
+# Read and parse the hex-dump output.
+hex="[0-9a-f]"
+hex_8="$hex$hex$hex$hex$hex$hex$hex$hex"
+hexspc="[0-9a-f ]"
+hexspc_8="$hexspc$hexspc$hexspc$hexspc$hexspc$hexspc$hexspc$hexspc"
+
+raw32()
+{
+       readelf --hex-dump "$2" "$1" 2>/dev/null |
+       sed \
+               -e '/^Hex/d' -e '/^$/d' -e '/^ *NOTE/d' \
+               -e 's/  *[^ ][^ ]*  *\('"$hex_8"'\) \('"$hexspc_8"'\) \('"$hexspc_8"'\) \('"$hexspc_8"'\) .*/\1 \2 \3 \4 /' \
+               -e 's/\('"$hex$hex"'\)\('"$hex$hex"'\)\('"$hex$hex"'\)\('"$hex$hex"'\) /\4\3\2\1 /g' \
+               -e 's/ $//g' -e 's/ /\n/g'
+}
+#-e 's/\([^ ][^ ][^ ][^ ][^ ][^ ][^ ][^ ]\) \([^ ][^ ][^ ][^ ][^ ][^ ][^ ][^ ]\) /\2\1 /g' \
+
+rela()
+{
+       #file="$(basename "$1")"
+       file="$1"
+
+       # Read relocation information for a 64bit binary.  Each relocation entry
+       # is 3 long longs so we collect 6 quads here.  Note that the dump is in
+       # listed in increasing byte order not withstanding the quad split.
+       #
+       # The record says to take the value of <symbol> add <symbol offset> and
+       # shove that into <write offset> in the segment of the <symbol>.
+       #
+       # Format:
+       #  <write offset>       64 bits
+       #  <symbol number>      32 bits
+       #  <relocation type>    32 bits
+       #  <symbol offset>      64 bits
+       raw32 "$1" ".rela$SECTION" | \
+       {
+               a1=''; a2=''; a3=''; a4=''; a5=''
+               while read a6
+               do
+                       [ "$a1" = '' ] && { a1="$a6"; continue; }
+                       [ "$a2" = '' ] && { a2="$a6"; continue; }
+                       [ "$a3" = '' ] && { a3="$a6"; continue; }
+                       [ "$a4" = '' ] && { a4="$a6"; continue; }
+                       [ "$a5" = '' ] && { a5="$a6"; continue; }
+
+                       #echo ">$a1< >$a2< >$a3< >$a4< >$a5< >$a6<" 1>&2
+                       #echo "type<$a3> symbol<$a4> offset<$a2$a1> addr<$a6a5>" 1>&2
+
+                       symbolmap "$a4"; section_num="$RET"
+                       #echo "section_num<$section_num>" 1>&2
+
+                       sectionmap "$section_num"; section="$RET"
+                       sectionvma "$section_num"; vma="$RET"
+                       #echo "section<$section> vma<$vma>" 1>&2
+
+                       # Adjust the segment addressing by the segment offset.
+                       printf -v addr "%u" "0x$a6$a5"
+                       printf -v vma "%u" "0x$vma"
+                       let offset="$addr + $vma"
+                       printf -v offset "%x" "$offset"
+
+                       echo "$file-$section-$offset"
+
+                       a1=''; a2=''; a3=''; a4=''; a5=''
+               done
+       } | sed -e 's/-00*\([0-9a-f]\)/-\1/'
+}
+
+# Form an associative lookup for the raw contents for an ELF section.
+# Uses 8 character 0 expanded hexadecimal key for ease of consumption.
+contentmap_init()
+{
+       raw32 "$1" "$2" >"$tmp.cm"
+       let offset=0
+       while read value
+       do
+               printf -v offset_hex "%08x" $offset
+               eval contentmap_$offset_hex=\'$value\'
+
+               let offset="$offset + 4"
+       done <"$tmp.cm"
+       rm -f "$tmp.cm"
+}
+contentmap()
+{
+       eval RET="\$contentmap_$1"
+       if [ "$RET" = '' ]; then
+               echo "contentmap: $1: invalid offset" 1>&2
+               exit 1
+       fi
+}
+
+rel()
+{
+       # Load up the current contents of the $SECTION segment
+       # as the offsets (see below) are recorded there and we will need
+       # those to calculate the actuall address.
+       contentmap_init "$1" "$SECTION"
+
+       #file="$(basename "$1")"
+       file="$1"
+
+       # Read relocation information for a 32bit binary.  Each relocation entry
+       # is 3 longs so we collect 3 quads here.  Note that the dump is in
+       # listed in increasing byte order not withstanding the quad split.
+       #
+       # The record says to take the value of <symbol> and add that to the
+       # existing contents of <write offset> in the segment of the <symbol>.
+       #
+       # Format:
+       #  <write offset>       32 bits
+       #  <symbol number>      24 bits
+       #  <relocation type>     8 bits
+       raw32 "$1" ".rel$SECTION" | \
+       {
+               a1=''
+               while read a2
+               do
+                       [ "$a1" = '' ] && { a1="$a2"; continue; }
+
+                       #echo ">$a1< >$a2<"
+                       contentmap "$a1"; offset="$RET"
+                       symbolmap "00${a2%??}"; section_num="$RET"
+
+                       sectionmap "$section_num"; section="$RET"
+                       sectionvma "$section_num"; vma="$RET"
+                       #echo ">$a1< >$a2< >$offset< >$section<"
+
+                       echo "$file-$section-$offset"
+
+                       a1=''
+               done
+       } | sed -e 's/-00*\([0-9a-f]\)/-\1/'
+}
+
+tmp="/tmp/retpoline-extract.$$"
+
+# Accumulate potentially vunerable indirect call/jmp sequences.  We do this
+# by examining the raw disassembly for affected forms, recording the location
+# of each.
+case "$bit16" in
+'')    ;;
+*)     disassemble_as='--disassembler-options=i8086' ;;
+esac
+objdump $disassemble_as --disassemble --no-show-raw-insn "$object" | \
+awk -F' ' '
+       BEGIN                           { file="'"$object"'"; src="'"$src"'"; }
+       /Disassembly of section/        { segment=$4; sub(":", "", segment); }
+       /^[0-9a-f][0-9a-f]* <.*>:/      { tag=$0; sub(".*<", "", tag); sub(">.*", "", tag); }
+       $0 ~ /(call|jmp)q?  *\*.*%/ {
+               sub(":", "", $1);
+               if (segment != ".init.text") {
+                       offset=$1
+                       $1=tag
+                       print(file "-" segment "-" offset " " src " " segment " " $0);
+               }
+       }
+' | sort -k 1b,1 >"$object.ur-detected"
+[ ! -s "$object.ur-detected" ] && rm -f "$object.ur-detected"
+
+# Load up the symbol table and section mappings.
+symbolmap_init "$object"
+sectionmap_init "$object"
+
+# Accumulate annotated safe indirect call/jmp sequences.  We do this by examining
+# the $SECTION sections (and their associated relocation information),
+# each entry represents the address of an instruction which has been marked
+# as ok.
+case "$section_relocation" in
+REL)   rel "$object" ;;
+RELA)  rela "$object" ;;
+esac | sort -k 1b,1 >"$object.ur-safe"
+[ ! -s "$object.ur-safe" ] && rm -f "$object.ur-safe"
+
+# We will perform the below join on the summarised and sorted fragments
+# formed above.  This is performed in retpoline-check.
+#join -v 1 -j 1 "$tmp.extracted" "$tmp.safe" | sed -s 's/[^ ]*  *//'
+
+rm -f "$tmp".*
index 436005392047b73486de4c86cf08d17de0bf0b66..9684c1091e62c3cf5ee80e001adbf8ae46151d69 100644 (file)
@@ -282,11 +282,18 @@ objtool_dep = $(objtool_obj)                                      \
              $(wildcard include/config/orc/unwinder.h          \
                         include/config/stack/validation.h)
 
+ifdef CONFIG_RETPOLINE
+cmd_ubuntu_retpoline = $(CONFIG_SHELL) $(srctree)/debian/scripts/retpoline-extract-one $(@) $(<) "$(filter -m16 %code16gcc.h,$(a_flags))";
+else
+cmd_ubuntu_retpoline =
+endif
+
 define rule_cc_o_c
        $(call echo-cmd,checksrc) $(cmd_checksrc)                         \
        $(call cmd_and_fixdep,cc_o_c)                                     \
        $(cmd_modversions_c)                                              \
        $(call echo-cmd,objtool) $(cmd_objtool)                           \
+       $(call echo-cmd,ubuntu-retpoline) $(cmd_ubuntu_retpoline)         \
        $(call echo-cmd,record_mcount) $(cmd_record_mcount)
 endef
 
@@ -294,6 +301,7 @@ define rule_as_o_S
        $(call cmd_and_fixdep,as_o_S)                                     \
        $(cmd_modversions_S)                                              \
        $(call echo-cmd,objtool) $(cmd_objtool)
+       $(call echo-cmd,ubuntu-retpoline) $(cmd_ubuntu_retpoline)
 endef
 
 # List module undefined symbols (or empty line if not enabled)