Re: [PATCH 0/1] RFC: Revamp admin-guide/tainted-kernels.rst to make it more comprehensible

From: Thorsten Leemhuis
Date: Thu Dec 20 2018 - 10:23:45 EST


Hi! Am 17.12.18 um 22:06 schrieb Randy Dunlap:
> On 12/17/18 10:24 AM, Jonathan Corbet wrote:
>> Here's an idea if you feel like improving this: rather than putting an
>> inscrutable program inline, add a taint_status script to scripts/ that
>> prints out the status in fully human-readable form, with the explanation
>> for every set bit.
> And some people prefer not adding tools that use python, perl, etc.

Yeah, I know :-/ On twitter @apexo (thx!) suggested these two:

dc -e"[00000000000000]n2o$(cat /proc/sys/kernel/tainted)p"|fold
-w1|tac|nl| grep -m 18 '.'

(echo -n 000000000000000;(echo obase=2;cat
/proc/sys/kernel/tainted)|bc)|fold -w1|tac|nl| grep -m 18 '.'

But it needs bc, which often is not installed by default :-/ Any as you
mentioned already: using Perl (

perl -e 'printf("%016b\n",<STDIN>)' < /proc/sys/kernel/tainted |fold
-w1|tac|nl

) also has it downsides. Having something that works in plain bash/sh
would be great...

Nevertheless: I'm still inclined to put a one liner decode command into
tainted-kernels.rst so people can decode the file easily even if they do
not have attached script at hand.

> E.g., I use this shell script (named 'chktaint', which could probably
> be done better):

Many thx. Find a slightly improved version attached that directly prints
the reason. I assume that's more like what Jonathan had in mind. The
script now is also capable of decoding a value retrieved from
/proc/sys/kernel/tainted on another system.

Randy, do you spot any problems or bashisms in the code? BTW, can I have
your "Signed-off-by" for the submission?

While at it: Jonathan, you mentioned putting the script in scripts/, but
according to the Makefile in that directory it is "for various helper
programs used throughout the kernel for the build process". That's one
reason why it feels wrong to put it there. Another one: that script
targets users and thus we should try to make sure they can access it
easily. That's why I'm currently inclined to put it in tools/ somewhere.
But I'm still unsure where. tools/scripts/ is used for something else
already, so maybe tools/helper-scripts/ or something? Putting it there
and installing it by default when building tools/ afaics increases the
chances a lot that distros will actually ship it in their packages that
contain tools from that directory.

Ciao, Thorsten
#! /bin/sh
# SPDX-License-Identifier: GPL-2.0
#
# Randy Dunlap <rdunlap@xxxxxxxxxxxxx>, 2018
# Thorsten Leemhuis <linux@xxxxxxxxxxxxx>, 2018

usage()
{
cat <<EOF
usage: ${0##*/}
${0##*/} <int>

Call without parameters to decode /proc/sys/kernel/tainted.

Call with a positive integer as parameter to decode a value you
retrieved from /proc/sys/kernel/tainted on another system.

EOF
}

if [ "$1"x != "x" ]; then
if [ "$1"x == "--helpx" ] || [ "$1"x == "-hx" ] ; then
usage
exit 1
elif [ $1 -ge 0 ] 2>/dev/null ; then
taint=$1
else
echo "Error: Parameter '$1' not a positive interger. Aborting." >&2
exit 1
fi
else
TAINTFILE="/proc/sys/kernel/tainted"
if [ ! -r $TAINTFILE ]; then
echo "No file: $TAINTFILE"
exit
fi

taint=`cat $TAINTFILE`
fi

if [ $taint -eq 0 ]; then
echo "Kernel not Tainted"
exit
else
echo "Kernel is Tainted for follwing reasons:"
fi

T=$taint
out=

addout() {
out=$out$1
}

if [ `expr $T % 2` -eq 0 ]; then
addout "G"
else
addout "P"
echo " * Proprietary module was loaded."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "F"
echo " * Module was force loaded."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "S"
echo " * SMP kernel oops on an officially SMP incapable processor."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "R"
echo " * Module was force unloaded."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "M"
echo " * Processor reported a Machine Check Exception (MCE)."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "B"
echo " * Bad page referenced or some unexpected page flags."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "U"
echo " * Taint requested by userspace application."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "D"
echo " * Kernel died recently, i.e. there was an OOPS or BUG"
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "A"
echo " * ACPI table overridden by user."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "W"
echo " * Kernel issued warning."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "C"
echo " * Staging driver was loaded."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "I"
echo " * Workaround for bug in platform firmware applied."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "O"
echo " * Externally-built ('out-of-tree') module was loaded"
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "E"
echo " * Unsigned module was loaded."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "L"
echo " * Soft lockup occurred."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "K"
echo " * Kernel live patched."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "X"
echo " * Auxiliary taint, defined for and used by distros."
fi

T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "T"
echo " * Kernel was built with the struct randomization plugin."
fi

echo "Raw taint value as int/string: $taint/'$out'"
#EOF#