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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
|
#!/usr/bin/env bash
set -e
EXITCODE=0
# bits of this were adapted from lxc-checkconfig
# see also https://github.com/lxc/lxc/blob/lxc-1.0.2/src/lxc/lxc-checkconfig.in
possibleConfigs=(
'/proc/config.gz'
"/boot/config-$(uname -r)"
"/usr/src/linux-$(uname -r)/.config"
'/usr/src/linux/.config'
)
if [ $# -gt 0 ]; then
CONFIG="$1"
else
: "${CONFIG:="${possibleConfigs[0]}"}"
fi
if ! command -v zgrep &> /dev/null; then
zgrep() {
zcat "$2" | grep "$1"
}
fi
kernelVersion="$(uname -r)"
kernelMajor="${kernelVersion%%.*}"
kernelMinor="${kernelVersion#$kernelMajor.}"
kernelMinor="${kernelMinor%%.*}"
is_set() {
zgrep "CONFIG_$1=[y|m]" "$CONFIG" > /dev/null
}
is_set_in_kernel() {
zgrep "CONFIG_$1=y" "$CONFIG" > /dev/null
}
is_set_as_module() {
zgrep "CONFIG_$1=m" "$CONFIG" > /dev/null
}
color() {
local codes=()
if [ "$1" = 'bold' ]; then
codes=("${codes[@]}" '1')
shift
fi
if [ "$#" -gt 0 ]; then
local code=
case "$1" in
# see https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
black) code=30 ;;
red) code=31 ;;
green) code=32 ;;
yellow) code=33 ;;
blue) code=34 ;;
magenta) code=35 ;;
cyan) code=36 ;;
white) code=37 ;;
esac
if [ "$code" ]; then
codes=("${codes[@]}" "$code")
fi
fi
local IFS=';'
echo -en '\033['"${codes[*]}"'m'
}
wrap_color() {
text="$1"
shift
color "$@"
echo -n "$text"
color reset
echo
}
wrap_good() {
echo "$(wrap_color "$1" white): $(wrap_color "$2" green)"
}
wrap_bad() {
echo "$(wrap_color "$1" bold): $(wrap_color "$2" bold red)"
}
wrap_warning() {
wrap_color >&2 "$*" red
}
check_flag() {
if is_set_in_kernel "$1"; then
wrap_good "CONFIG_$1" 'enabled'
elif is_set_as_module "$1"; then
wrap_good "CONFIG_$1" 'enabled (as module)'
else
wrap_bad "CONFIG_$1" 'missing'
EXITCODE=1
fi
}
check_flags() {
for flag in "$@"; do
echo -n "- "
check_flag "$flag"
done
}
check_command() {
if command -v "$1" > /dev/null 2>&1; then
wrap_good "$1 command" 'available'
else
wrap_bad "$1 command" 'missing'
EXITCODE=1
fi
}
check_device() {
if [ -c "$1" ]; then
wrap_good "$1" 'present'
else
wrap_bad "$1" 'missing'
EXITCODE=1
fi
}
check_distro_userns() {
source /etc/os-release 2> /dev/null || /bin/true
if [[ "${ID}" =~ ^(centos|rhel)$ && "${VERSION_ID}" =~ ^7 ]]; then
# this is a CentOS7 or RHEL7 system
grep -q "user_namespace.enable=1" /proc/cmdline || {
# no user namespace support enabled
wrap_bad " (RHEL7/CentOS7" "User namespaces disabled; add 'user_namespace.enable=1' to boot command line)"
EXITCODE=1
}
fi
}
if [ ! -e "$CONFIG" ]; then
wrap_warning "warning: $CONFIG does not exist, searching other paths for kernel config ..."
for tryConfig in "${possibleConfigs[@]}"; do
if [ -e "$tryConfig" ]; then
CONFIG="$tryConfig"
break
fi
done
if [ ! -e "$CONFIG" ]; then
wrap_warning "error: cannot find kernel config"
wrap_warning " try running this script again, specifying the kernel config:"
wrap_warning " CONFIG=/path/to/kernel/.config $0 or $0 /path/to/kernel/.config"
exit 1
fi
fi
wrap_color "info: reading kernel config from $CONFIG ..." white
echo
echo 'Generally Necessary:'
echo -n '- '
if [ "$(stat -f -c %t /sys/fs/cgroup 2> /dev/null)" = '63677270' ]; then
echo "$(wrap_good 'cgroup hierarchy' 'cgroupv2')"
else
cgroupSubsystemDir="$(awk '/[, ](cpu|cpuacct|cpuset|devices|freezer|memory)[, ]/ && $3 == "cgroup" { print $2 }' /proc/mounts | head -n1)"
cgroupDir="$(dirname "$cgroupSubsystemDir")"
if [ -d "$cgroupDir/cpu" ] || [ -d "$cgroupDir/cpuacct" ] || [ -d "$cgroupDir/cpuset" ] || [ -d "$cgroupDir/devices" ] || [ -d "$cgroupDir/freezer" ] || [ -d "$cgroupDir/memory" ]; then
echo "$(wrap_good 'cgroup hierarchy' 'properly mounted') [$cgroupDir]"
else
if [ "$cgroupSubsystemDir" ]; then
echo "$(wrap_bad 'cgroup hierarchy' 'single mountpoint!') [$cgroupSubsystemDir]"
else
wrap_bad 'cgroup hierarchy' 'nonexistent??'
fi
EXITCODE=1
echo " $(wrap_color '(see https://github.com/tianon/cgroupfs-mount)' yellow)"
fi
fi
if [ "$(cat /sys/module/apparmor/parameters/enabled 2> /dev/null)" = 'Y' ]; then
echo -n '- '
if command -v apparmor_parser &> /dev/null; then
wrap_good 'apparmor' 'enabled and tools installed'
else
wrap_bad 'apparmor' 'enabled, but apparmor_parser missing'
echo -n ' '
if command -v apt-get &> /dev/null; then
wrap_color '(use "apt-get install apparmor" to fix this)'
elif command -v yum &> /dev/null; then
wrap_color '(your best bet is "yum install apparmor-parser")'
else
wrap_color '(look for an "apparmor" package for your distribution)'
fi
EXITCODE=1
fi
fi
flags=(
NAMESPACES {NET,PID,IPC,UTS}_NS
CGROUPS CGROUP_CPUACCT CGROUP_DEVICE CGROUP_FREEZER CGROUP_SCHED CPUSETS MEMCG
KEYS
VETH BRIDGE BRIDGE_NETFILTER
IP_NF_FILTER IP_NF_TARGET_MASQUERADE
NETFILTER_XT_MATCH_{ADDRTYPE,CONNTRACK,IPVS}
NETFILTER_XT_MARK
IP_NF_NAT NF_NAT
# required for bind-mounting /dev/mqueue into containers
POSIX_MQUEUE
)
check_flags "${flags[@]}"
if [ "$kernelMajor" -lt 4 ] || ([ "$kernelMajor" -eq 4 ] && [ "$kernelMinor" -lt 8 ]); then
check_flags DEVPTS_MULTIPLE_INSTANCES
fi
if [ "$kernelMajor" -lt 5 ] || [ "$kernelMajor" -eq 5 -a "$kernelMinor" -le 1 ]; then
check_flags NF_NAT_IPV4
fi
if [ "$kernelMajor" -lt 5 ] || [ "$kernelMajor" -eq 5 -a "$kernelMinor" -le 2 ]; then
check_flags NF_NAT_NEEDED
fi
echo
echo 'Optional Features:'
{
check_flags USER_NS
check_distro_userns
}
{
check_flags SECCOMP
}
{
check_flags CGROUP_PIDS
}
{
check_flags MEMCG_SWAP
# Kernel v5.8+ removes MEMCG_SWAP_ENABLED.
if [ "$kernelMajor" -lt 5 ] || [ "$kernelMajor" -eq 5 -a "$kernelMinor" -le 8 ]; then
CODE=${EXITCODE}
check_flags MEMCG_SWAP_ENABLED
# FIXME this check is cgroupv1-specific
if [ -e /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes ]; then
echo " $(wrap_color '(cgroup swap accounting is currently enabled)' bold black)"
EXITCODE=${CODE}
elif is_set MEMCG_SWAP && ! is_set MEMCG_SWAP_ENABLED; then
echo " $(wrap_color '(cgroup swap accounting is currently not enabled, you can enable it by setting boot option "swapaccount=1")' bold black)"
fi
else
# Kernel v5.8+ enables swap accounting by default.
echo " $(wrap_color '(cgroup swap accounting is currently enabled)' bold black)"
fi
}
{
if is_set LEGACY_VSYSCALL_NATIVE; then
echo -n "- "
wrap_bad "CONFIG_LEGACY_VSYSCALL_NATIVE" 'enabled'
echo " $(wrap_color '(dangerous, provides an ASLR-bypassing target with usable ROP gadgets.)' bold black)"
elif is_set LEGACY_VSYSCALL_EMULATE; then
echo -n "- "
wrap_good "CONFIG_LEGACY_VSYSCALL_EMULATE" 'enabled'
elif is_set LEGACY_VSYSCALL_NONE; then
echo -n "- "
wrap_bad "CONFIG_LEGACY_VSYSCALL_NONE" 'enabled'
echo " $(wrap_color '(containers using eglibc <= 2.13 will not work. Switch to' bold black)"
echo " $(wrap_color ' "CONFIG_VSYSCALL_[NATIVE|EMULATE]" or use "vsyscall=[native|emulate]"' bold black)"
echo " $(wrap_color ' on kernel command line. Note that this will disable ASLR for the,' bold black)"
echo " $(wrap_color ' VDSO which may assist in exploiting security vulnerabilities.)' bold black)"
# else Older kernels (prior to 3dc33bd30f3e, released in v4.40-rc1) do
# not have these LEGACY_VSYSCALL options and are effectively
# LEGACY_VSYSCALL_EMULATE. Even older kernels are presumably
# effectively LEGACY_VSYSCALL_NATIVE.
fi
}
if [ "$kernelMajor" -lt 4 ] || ([ "$kernelMajor" -eq 4 ] && [ "$kernelMinor" -le 5 ]); then
check_flags MEMCG_KMEM
fi
if [ "$kernelMajor" -lt 3 ] || ([ "$kernelMajor" -eq 3 ] && [ "$kernelMinor" -le 18 ]); then
check_flags RESOURCE_COUNTERS
fi
if [ "$kernelMajor" -lt 3 ] || ([ "$kernelMajor" -eq 3 ] && [ "$kernelMinor" -le 13 ]); then
netprio=NETPRIO_CGROUP
else
netprio=CGROUP_NET_PRIO
fi
if [ "$kernelMajor" -lt 5 ]; then
check_flags IOSCHED_CFQ CFQ_GROUP_IOSCHED
fi
flags=(
BLK_CGROUP BLK_DEV_THROTTLING
CGROUP_PERF
CGROUP_HUGETLB
NET_CLS_CGROUP $netprio
CFS_BANDWIDTH FAIR_GROUP_SCHED RT_GROUP_SCHED
IP_NF_TARGET_REDIRECT
IP_VS
IP_VS_NFCT
IP_VS_PROTO_TCP
IP_VS_PROTO_UDP
IP_VS_RR
)
check_flags "${flags[@]}"
if ! is_set EXT4_USE_FOR_EXT2; then
check_flags EXT3_FS EXT3_FS_XATTR EXT3_FS_POSIX_ACL EXT3_FS_SECURITY
if ! is_set EXT3_FS || ! is_set EXT3_FS_XATTR || ! is_set EXT3_FS_POSIX_ACL || ! is_set EXT3_FS_SECURITY; then
echo " $(wrap_color '(enable these ext3 configs if you are using ext3 as backing filesystem)' bold black)"
fi
fi
check_flags EXT4_FS EXT4_FS_POSIX_ACL EXT4_FS_SECURITY
if ! is_set EXT4_FS || ! is_set EXT4_FS_POSIX_ACL || ! is_set EXT4_FS_SECURITY; then
if is_set EXT4_USE_FOR_EXT2; then
echo " $(wrap_color 'enable these ext4 configs if you are using ext3 or ext4 as backing filesystem' bold black)"
else
echo " $(wrap_color 'enable these ext4 configs if you are using ext4 as backing filesystem' bold black)"
fi
fi
echo '- Network Drivers:'
echo " - \"$(wrap_color 'overlay' blue)\":"
check_flags VXLAN BRIDGE_VLAN_FILTERING | sed 's/^/ /'
echo ' Optional (for encrypted networks):'
check_flags CRYPTO CRYPTO_AEAD CRYPTO_GCM CRYPTO_SEQIV CRYPTO_GHASH \
XFRM XFRM_USER XFRM_ALGO INET_ESP | sed 's/^/ /'
if [ "$kernelMajor" -lt 5 ] || [ "$kernelMajor" -eq 5 -a "$kernelMinor" -le 3 ]; then
check_flags INET_XFRM_MODE_TRANSPORT | sed 's/^/ /'
fi
echo " - \"$(wrap_color 'ipvlan' blue)\":"
check_flags IPVLAN | sed 's/^/ /'
echo " - \"$(wrap_color 'macvlan' blue)\":"
check_flags MACVLAN DUMMY | sed 's/^/ /'
echo " - \"$(wrap_color 'ftp,tftp client in container' blue)\":"
check_flags NF_NAT_FTP NF_CONNTRACK_FTP NF_NAT_TFTP NF_CONNTRACK_TFTP | sed 's/^/ /'
# only fail if no storage drivers available
CODE=${EXITCODE}
EXITCODE=0
STORAGE=1
echo '- Storage Drivers:'
echo " - \"$(wrap_color 'aufs' blue)\":"
check_flags AUFS_FS | sed 's/^/ /'
if ! is_set AUFS_FS && grep -q aufs /proc/filesystems; then
echo " $(wrap_color '(note that some kernels include AUFS patches but not the AUFS_FS flag)' bold black)"
fi
[ "$EXITCODE" = 0 ] && STORAGE=0
EXITCODE=0
echo " - \"$(wrap_color 'btrfs' blue)\":"
check_flags BTRFS_FS | sed 's/^/ /'
check_flags BTRFS_FS_POSIX_ACL | sed 's/^/ /'
[ "$EXITCODE" = 0 ] && STORAGE=0
EXITCODE=0
echo " - \"$(wrap_color 'devicemapper' blue)\":"
check_flags BLK_DEV_DM DM_THIN_PROVISIONING | sed 's/^/ /'
[ "$EXITCODE" = 0 ] && STORAGE=0
EXITCODE=0
echo " - \"$(wrap_color 'overlay' blue)\":"
check_flags OVERLAY_FS | sed 's/^/ /'
[ "$EXITCODE" = 0 ] && STORAGE=0
EXITCODE=0
echo " - \"$(wrap_color 'zfs' blue)\":"
echo -n " - "
check_device /dev/zfs
echo -n " - "
check_command zfs
echo -n " - "
check_command zpool
[ "$EXITCODE" = 0 ] && STORAGE=0
EXITCODE=0
EXITCODE=$CODE
[ "$STORAGE" = 1 ] && EXITCODE=1
echo
check_limit_over() {
if [ "$(cat "$1")" -le "$2" ]; then
wrap_bad "- $1" "$(cat "$1")"
wrap_color " This should be set to at least $2, for example set: sysctl -w kernel/keys/root_maxkeys=1000000" bold black
EXITCODE=1
else
wrap_good "- $1" "$(cat "$1")"
fi
}
echo 'Limits:'
check_limit_over /proc/sys/kernel/keys/root_maxkeys 10000
echo
exit $EXITCODE
|