1. #!/usr/bin/env bash
    2. set -e
    3. EXITCODE=0
    4. # bits of this were adapted from lxc-checkconfig
    5. # see also https://github.com/lxc/lxc/blob/lxc-1.0.2/src/lxc/lxc-checkconfig.in
    6. possibleConfigs=(
    7. '/proc/config.gz'
    8. "/boot/config-$(uname -r)"
    9. "/usr/src/linux-$(uname -r)/.config"
    10. '/usr/src/linux/.config'
    11. )
    12. if [ $# -gt 0 ]; then
    13. CONFIG="$1"
    14. else
    15. : "${CONFIG:="${possibleConfigs[0]}"}"
    16. fi
    17. if ! command -v zgrep &>/dev/null; then
    18. zgrep() {
    19. zcat "$2" | grep "$1"
    20. }
    21. fi
    22. kernelVersion="$(uname -r)"
    23. kernelMajor="${kernelVersion%%.*}"
    24. kernelMinor="${kernelVersion#$kernelMajor.}"
    25. kernelMinor="${kernelMinor%%.*}"
    26. is_set() {
    27. zgrep "CONFIG_$1=[y|m]" "$CONFIG" >/dev/null
    28. }
    29. is_set_in_kernel() {
    30. zgrep "CONFIG_$1=y" "$CONFIG" >/dev/null
    31. }
    32. is_set_as_module() {
    33. zgrep "CONFIG_$1=m" "$CONFIG" >/dev/null
    34. }
    35. color() {
    36. local codes=()
    37. if [ "$1" = 'bold' ]; then
    38. codes=("${codes[@]}" '1')
    39. shift
    40. fi
    41. if [ "$#" -gt 0 ]; then
    42. local code=
    43. case "$1" in
    44. # see https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
    45. black) code=30 ;;
    46. red) code=31 ;;
    47. green) code=32 ;;
    48. yellow) code=33 ;;
    49. blue) code=34 ;;
    50. magenta) code=35 ;;
    51. cyan) code=36 ;;
    52. white) code=37 ;;
    53. esac
    54. if [ "$code" ]; then
    55. codes=("${codes[@]}" "$code")
    56. fi
    57. fi
    58. local IFS=';'
    59. echo -en '\033['"${codes[*]}"'m'
    60. }
    61. wrap_color() {
    62. text="$1"
    63. shift
    64. color "$@"
    65. echo -n "$text"
    66. color reset
    67. echo
    68. }
    69. wrap_good() {
    70. echo "$(wrap_color "$1" white): $(wrap_color "$2" green)"
    71. }
    72. wrap_bad() {
    73. echo "$(wrap_color "$1" bold): $(wrap_color "$2" bold red)"
    74. }
    75. wrap_warning() {
    76. wrap_color >&2 "$*" red
    77. }
    78. check_flag() {
    79. if is_set_in_kernel "$1"; then
    80. wrap_good "CONFIG_$1" 'enabled'
    81. elif is_set_as_module "$1"; then
    82. wrap_good "CONFIG_$1" 'enabled (as module)'
    83. else
    84. wrap_bad "CONFIG_$1" 'missing'
    85. EXITCODE=1
    86. fi
    87. }
    88. check_flags() {
    89. for flag in "$@"; do
    90. echo -n "- "
    91. check_flag "$flag"
    92. done
    93. }
    94. check_command() {
    95. if command -v "$1" >/dev/null 2>&1; then
    96. wrap_good "$1 command" 'available'
    97. else
    98. wrap_bad "$1 command" 'missing'
    99. EXITCODE=1
    100. fi
    101. }
    102. check_device() {
    103. if [ -c "$1" ]; then
    104. wrap_good "$1" 'present'
    105. else
    106. wrap_bad "$1" 'missing'
    107. EXITCODE=1
    108. fi
    109. }
    110. check_distro_userns() {
    111. source /etc/os-release 2>/dev/null || /bin/true
    112. if [[ "${ID}" =~ ^(centos|rhel)$ && "${VERSION_ID}" =~ ^7 ]]; then
    113. # this is a CentOS7 or RHEL7 system
    114. grep -q "user_namespace.enable=1" /proc/cmdline || {
    115. # no user namespace support enabled
    116. wrap_bad " (RHEL7/CentOS7" "User namespaces disabled; add 'user_namespace.enable=1' to boot command line)"
    117. EXITCODE=1
    118. }
    119. fi
    120. }
    121. if [ ! -e "$CONFIG" ]; then
    122. wrap_warning "warning: $CONFIG does not exist, searching other paths for kernel config ..."
    123. for tryConfig in "${possibleConfigs[@]}"; do
    124. if [ -e "$tryConfig" ]; then
    125. CONFIG="$tryConfig"
    126. break
    127. fi
    128. done
    129. if [ ! -e "$CONFIG" ]; then
    130. wrap_warning "error: cannot find kernel config"
    131. wrap_warning " try running this script again, specifying the kernel config:"
    132. wrap_warning " CONFIG=/path/to/kernel/.config $0 or $0 /path/to/kernel/.config"
    133. exit 1
    134. fi
    135. fi
    136. wrap_color "info: reading kernel config from $CONFIG ..." white
    137. echo
    138. echo 'Generally Necessary:'
    139. echo -n '- '
    140. cgroupSubsystemDir="$(awk '/[, ](cpu|cpuacct|cpuset|devices|freezer|memory)[, ]/ && $3 == "cgroup" { print $2 }' /proc/mounts | head -n1)"
    141. cgroupDir="$(dirname "$cgroupSubsystemDir")"
    142. if [ -d "$cgroupDir/cpu" ] || [ -d "$cgroupDir/cpuacct" ] || [ -d "$cgroupDir/cpuset" ] || [ -d "$cgroupDir/devices" ] || [ -d "$cgroupDir/freezer" ] || [ -d "$cgroupDir/memory" ]; then
    143. echo "$(wrap_good 'cgroup hierarchy' 'properly mounted') [$cgroupDir]"
    144. else
    145. if [ "$cgroupSubsystemDir" ]; then
    146. echo "$(wrap_bad 'cgroup hierarchy' 'single mountpoint!') [$cgroupSubsystemDir]"
    147. else
    148. wrap_bad 'cgroup hierarchy' 'nonexistent??'
    149. fi
    150. EXITCODE=1
    151. echo " $(wrap_color '(see https://github.com/tianon/cgroupfs-mount)' yellow)"
    152. fi
    153. if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = 'Y' ]; then
    154. echo -n '- '
    155. if command -v apparmor_parser &>/dev/null; then
    156. wrap_good 'apparmor' 'enabled and tools installed'
    157. else
    158. wrap_bad 'apparmor' 'enabled, but apparmor_parser missing'
    159. echo -n ' '
    160. if command -v apt-get &>/dev/null; then
    161. wrap_color '(use "apt-get install apparmor" to fix this)'
    162. elif command -v yum &>/dev/null; then
    163. wrap_color '(your best bet is "yum install apparmor-parser")'
    164. else
    165. wrap_color '(look for an "apparmor" package for your distribution)'
    166. fi
    167. EXITCODE=1
    168. fi
    169. fi
    170. flags=(
    171. NAMESPACES {NET,PID,IPC,UTS}_NS
    172. CGROUPS CGROUP_CPUACCT CGROUP_DEVICE CGROUP_FREEZER CGROUP_SCHED CPUSETS MEMCG
    173. KEYS
    174. VETH BRIDGE BRIDGE_NETFILTER
    175. NF_NAT_IPV4 IP_NF_FILTER IP_NF_TARGET_MASQUERADE
    176. NETFILTER_XT_MATCH_{ADDRTYPE,CONNTRACK,IPVS}
    177. IP_NF_NAT NF_NAT NF_NAT_NEEDED
    178. # required for bind-mounting /dev/mqueue into containers
    179. POSIX_MQUEUE
    180. )
    181. check_flags "${flags[@]}"
    182. if [ "$kernelMajor" -lt 4 ] || ([ "$kernelMajor" -eq 4 ] && [ "$kernelMinor" -lt 8 ]); then
    183. check_flags DEVPTS_MULTIPLE_INSTANCES
    184. fi
    185. echo
    186. echo 'Optional Features:'
    187. {
    188. check_flags USER_NS
    189. check_distro_userns
    190. }
    191. {
    192. check_flags SECCOMP
    193. }
    194. {
    195. check_flags CGROUP_PIDS
    196. }
    197. {
    198. CODE=${EXITCODE}
    199. check_flags MEMCG_SWAP MEMCG_SWAP_ENABLED
    200. if [ -e /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes ]; then
    201. echo " $(wrap_color '(cgroup swap accounting is currently enabled)' bold black)"
    202. EXITCODE=${CODE}
    203. elif is_set MEMCG_SWAP && ! is_set MEMCG_SWAP_ENABLED; then
    204. echo " $(wrap_color '(cgroup swap accounting is currently not enabled, you can enable it by setting boot option "swapaccount=1")' bold black)"
    205. fi
    206. }
    207. {
    208. if is_set LEGACY_VSYSCALL_NATIVE; then
    209. echo -n "- "
    210. wrap_bad "CONFIG_LEGACY_VSYSCALL_NATIVE" 'enabled'
    211. echo " $(wrap_color '(dangerous, provides an ASLR-bypassing target with usable ROP gadgets.)' bold black)"
    212. elif is_set LEGACY_VSYSCALL_EMULATE; then
    213. echo -n "- "
    214. wrap_good "CONFIG_LEGACY_VSYSCALL_EMULATE" 'enabled'
    215. elif is_set LEGACY_VSYSCALL_NONE; then
    216. echo -n "- "
    217. wrap_bad "CONFIG_LEGACY_VSYSCALL_NONE" 'enabled'
    218. echo " $(wrap_color '(containers using eglibc <= 2.13 will not work. Switch to' bold black)"
    219. echo " $(wrap_color ' "CONFIG_VSYSCALL_[NATIVE|EMULATE]" or use "vsyscall=[native|emulate]"' bold black)"
    220. echo " $(wrap_color ' on kernel command line. Note that this will disable ASLR for the,' bold black)"
    221. echo " $(wrap_color ' VDSO which may assist in exploiting security vulnerabilities.)' bold black)"
    222. # else Older kernels (prior to 3dc33bd30f3e, released in v4.40-rc1) do
    223. # not have these LEGACY_VSYSCALL options and are effectively
    224. # LEGACY_VSYSCALL_EMULATE. Even older kernels are presumably
    225. # effectively LEGACY_VSYSCALL_NATIVE.
    226. fi
    227. }
    228. if [ "$kernelMajor" -lt 4 ] || ([ "$kernelMajor" -eq 4 ] && [ "$kernelMinor" -le 5 ]); then
    229. check_flags MEMCG_KMEM
    230. fi
    231. if [ "$kernelMajor" -lt 3 ] || ([ "$kernelMajor" -eq 3 ] && [ "$kernelMinor" -le 18 ]); then
    232. check_flags RESOURCE_COUNTERS
    233. fi
    234. if [ "$kernelMajor" -lt 3 ] || ([ "$kernelMajor" -eq 3 ] && [ "$kernelMinor" -le 13 ]); then
    235. netprio=NETPRIO_CGROUP
    236. else
    237. netprio=CGROUP_NET_PRIO
    238. fi
    239. flags=(
    240. BLK_CGROUP BLK_DEV_THROTTLING IOSCHED_CFQ CFQ_GROUP_IOSCHED
    241. CGROUP_PERF
    242. CGROUP_HUGETLB
    243. NET_CLS_CGROUP $netprio
    244. CFS_BANDWIDTH FAIR_GROUP_SCHED RT_GROUP_SCHED
    245. IP_NF_TARGET_REDIRECT
    246. IP_VS
    247. IP_VS_NFCT
    248. IP_VS_PROTO_TCP
    249. IP_VS_PROTO_UDP
    250. IP_VS_RR
    251. )
    252. check_flags "${flags[@]}"
    253. if ! is_set EXT4_USE_FOR_EXT2; then
    254. check_flags EXT3_FS EXT3_FS_XATTR EXT3_FS_POSIX_ACL EXT3_FS_SECURITY
    255. if ! is_set EXT3_FS || ! is_set EXT3_FS_XATTR || ! is_set EXT3_FS_POSIX_ACL || ! is_set EXT3_FS_SECURITY; then
    256. echo " $(wrap_color '(enable these ext3 configs if you are using ext3 as backing filesystem)' bold black)"
    257. fi
    258. fi
    259. check_flags EXT4_FS EXT4_FS_POSIX_ACL EXT4_FS_SECURITY
    260. if ! is_set EXT4_FS || ! is_set EXT4_FS_POSIX_ACL || ! is_set EXT4_FS_SECURITY; then
    261. if is_set EXT4_USE_FOR_EXT2; then
    262. echo " $(wrap_color 'enable these ext4 configs if you are using ext3 or ext4 as backing filesystem' bold black)"
    263. else
    264. echo " $(wrap_color 'enable these ext4 configs if you are using ext4 as backing filesystem' bold black)"
    265. fi
    266. fi
    267. echo '- Network Drivers:'
    268. echo " - \"$(wrap_color 'overlay' blue)\":"
    269. check_flags VXLAN BRIDGE_VLAN_FILTERING | sed 's/^/ /'
    270. echo ' Optional (for encrypted networks):'
    271. check_flags CRYPTO CRYPTO_AEAD CRYPTO_GCM CRYPTO_SEQIV CRYPTO_GHASH \
    272. XFRM XFRM_USER XFRM_ALGO INET_ESP INET_XFRM_MODE_TRANSPORT | sed 's/^/ /'
    273. echo " - \"$(wrap_color 'ipvlan' blue)\":"
    274. check_flags IPVLAN | sed 's/^/ /'
    275. echo " - \"$(wrap_color 'macvlan' blue)\":"
    276. check_flags MACVLAN DUMMY | sed 's/^/ /'
    277. echo " - \"$(wrap_color 'ftp,tftp client in container' blue)\":"
    278. check_flags NF_NAT_FTP NF_CONNTRACK_FTP NF_NAT_TFTP NF_CONNTRACK_TFTP | sed 's/^/ /'
    279. # only fail if no storage drivers available
    280. CODE=${EXITCODE}
    281. EXITCODE=0
    282. STORAGE=1
    283. echo '- Storage Drivers:'
    284. echo " - \"$(wrap_color 'aufs' blue)\":"
    285. check_flags AUFS_FS | sed 's/^/ /'
    286. if ! is_set AUFS_FS && grep -q aufs /proc/filesystems; then
    287. echo " $(wrap_color '(note that some kernels include AUFS patches but not the AUFS_FS flag)' bold black)"
    288. fi
    289. [ "$EXITCODE" = 0 ] && STORAGE=0
    290. EXITCODE=0
    291. echo " - \"$(wrap_color 'btrfs' blue)\":"
    292. check_flags BTRFS_FS | sed 's/^/ /'
    293. check_flags BTRFS_FS_POSIX_ACL | sed 's/^/ /'
    294. [ "$EXITCODE" = 0 ] && STORAGE=0
    295. EXITCODE=0
    296. echo " - \"$(wrap_color 'devicemapper' blue)\":"
    297. check_flags BLK_DEV_DM DM_THIN_PROVISIONING | sed 's/^/ /'
    298. [ "$EXITCODE" = 0 ] && STORAGE=0
    299. EXITCODE=0
    300. echo " - \"$(wrap_color 'overlay' blue)\":"
    301. check_flags OVERLAY_FS | sed 's/^/ /'
    302. [ "$EXITCODE" = 0 ] && STORAGE=0
    303. EXITCODE=0
    304. echo " - \"$(wrap_color 'zfs' blue)\":"
    305. echo -n " - "
    306. check_device /dev/zfs
    307. echo -n " - "
    308. check_command zfs
    309. echo -n " - "
    310. check_command zpool
    311. [ "$EXITCODE" = 0 ] && STORAGE=0
    312. EXITCODE=0
    313. EXITCODE=$CODE
    314. [ "$STORAGE" = 1 ] && EXITCODE=1
    315. echo
    316. check_limit_over() {
    317. if [ "$(cat "$1")" -le "$2" ]; then
    318. wrap_bad "- $1" "$(cat "$1")"
    319. wrap_color " This should be set to at least $2, for example set: sysctl -w kernel/keys/root_maxkeys=1000000" bold black
    320. EXITCODE=1
    321. else
    322. wrap_good "- $1" "$(cat "$1")"
    323. fi
    324. }
    325. echo 'Limits:'
    326. check_limit_over /proc/sys/kernel/keys/root_maxkeys 10000
    327. echo
    328. exit $EXITCODE