diff --git a/docker/falco/docker-entrypoint.sh b/docker/falco/docker-entrypoint.sh index 8e852fd16f9..9147fe10feb 100755 --- a/docker/falco/docker-entrypoint.sh +++ b/docker/falco/docker-entrypoint.sh @@ -16,14 +16,9 @@ # limitations under the License. # -# todo(leogr): remove deprecation notice within a couple of releases -if [[ ! -z "${SKIP_MODULE_LOAD}" ]]; then - echo "* SKIP_MODULE_LOAD is deprecated and will be removed soon, use SKIP_DRIVER_LOADER instead" -fi - # Set the SKIP_DRIVER_LOADER variable to skip loading the driver -if [[ -z "${SKIP_DRIVER_LOADER}" ]] && [[ -z "${SKIP_MODULE_LOAD}" ]]; then +if [[ -z "${SKIP_DRIVER_LOADER}" ]]; then echo "* Setting up /usr/src links from host" for i in "$HOST_ROOT/usr/src"/* diff --git a/scripts/falco-driver-loader b/scripts/falco-driver-loader index ef4043f682c..a9395bc9a53 100755 --- a/scripts/falco-driver-loader +++ b/scripts/falco-driver-loader @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2019 The Falco Authors. +# Copyright (C) 2021 The Falco Authors. # # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ # limitations under the License. # # Simple script that desperately tries to load the kernel instrumentation by -# looking for it in a bunch of ways. Convenient when running falco inside +# looking for it in a bunch of ways. Convenient when running Falco inside # a container or in other weird environments. # @@ -82,7 +82,7 @@ get_kernel_config() { echo "* Found kernel config at ${HOST_ROOT}/usr/lib/ostree-boot/config-${KERNEL_RELEASE}" KERNEL_CONFIG_PATH="${HOST_ROOT}/usr/lib/ostree-boot/config-${KERNEL_RELEASE}" elif [ -f "/lib/modules/${KERNEL_RELEASE}/config" ]; then - # this code works both for native host and agent container assuming that + # This code works both for native host and containers assuming that # Dockerfile sets up the desired symlink /lib/modules -> $HOST_ROOT/lib/modules echo "* Found kernel config at /lib/modules/${KERNEL_RELEASE}/config" KERNEL_CONFIG_PATH="/lib/modules/${KERNEL_RELEASE}/config" @@ -107,12 +107,14 @@ get_target_id() { source "${HOST_ROOT}/etc/os-release" OS_ID=$ID elif [ -f "${HOST_ROOT}/etc/debian_version" ]; then - # Older Debian - # fixme > can this happen on older Ubuntu? + # Older debian distros + # fixme > Can this happen on older Ubuntu? OS_ID=debian elif [ -f "${HOST_ROOT}/etc/centos-release" ]; then - # Older CentOS + # Older CentOS distros OS_ID=centos + elif [ -f "${HOST_ROOT}/etc/VERSION" ]; then + OS_ID=minikube else >&2 echo "Detected an unsupported target system, please get in touch with the Falco community" exit 1 @@ -140,18 +142,18 @@ get_target_id() { } load_kernel_module_compile() { - # skip dkms on UEK hosts because it will always fail + # Skip dkms on UEK hosts because it will always fail if [[ $(uname -r) == *uek* ]]; then - echo "* Skipping dkms install for UEK host" + >&2 echo "Skipping because the dkms install always fail (on UEK hosts)" return fi - if ! hash dkms &>/dev/null; then - echo "* Skipping dkms install (dkms not found)" + if ! hash dkms >/dev/null 2>&1; then + >&2 echo "This program requires dkms" return fi - # try to compile using all the available gcc versions + # Try to compile using all the available gcc versions for CURRENT_GCC in $(which gcc) $(ls "$(dirname "$(which gcc)")"/gcc-* | grep 'gcc-[0-9]\+' | sort -r); do echo "* Trying to dkms install ${DRIVER_NAME} module with GCC ${CURRENT_GCC}" echo "#!/usr/bin/env bash" > /tmp/falco-dkms-make @@ -181,7 +183,6 @@ load_kernel_module_compile() { } load_kernel_module_download() { - get_target_id local FALCO_KERNEL_MODULE_FILENAME="${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.ko" @@ -189,14 +190,14 @@ load_kernel_module_download() { local URL URL=$(echo "${DRIVERS_REPO}/${DRIVER_VERSION}/${FALCO_KERNEL_MODULE_FILENAME}" | sed s/+/%2B/g) - echo "* Trying to download prebuilt module from ${URL}" + echo "* Trying to download a prebuilt ${DRIVER_NAME} module from ${URL}" if curl -L --create-dirs "${FALCO_DRIVER_CURL_OPTIONS}" -o "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" "${URL}"; then echo "* Download succeeded" - insmod "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" && echo "* Success: ${DRIVER_NAME} module loaded" + insmod "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" && echo "* Success: ${DRIVER_NAME} module found and inserted" exit $? else - >&2 echo "Download failed, consider compiling your own ${DRIVER_NAME} module and loading it or getting in touch with the Falco community" - exit 1 + >&2 echo "Unable to find a prebuilt ${DRIVER_NAME} module" + return fi } @@ -237,33 +238,35 @@ load_kernel_module() { exit 0 fi - if [ -n "$ENABLE_COMPILE" ]; then - load_kernel_module_compile - fi - - - echo "* Trying to load a system ${DRIVER_NAME} driver, if present" + echo "* Trying to load a system ${DRIVER_NAME} module, if present" if modprobe "${DRIVER_NAME}" > /dev/null 2>&1; then echo "* Success: ${DRIVER_NAME} module found and loaded with modprobe" exit 0 fi - - echo "* Trying to find locally a prebuilt ${DRIVER_NAME} module for kernel ${KERNEL_RELEASE}, if present" + echo "* Looking for a ${DRIVER_NAME} module locally (kernel ${KERNEL_RELEASE})" get_target_id local FALCO_KERNEL_MODULE_FILENAME="${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.ko" if [ -f "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" ]; then - echo "* Found a prebuilt module at ${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}, loading it" - insmod "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" && echo "* Success: ${DRIVER_NAME} module loaded" + echo "* Found a prebuilt ${DRIVER_NAME} module at ${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}, loading it" + insmod "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" && echo "* Success: ${DRIVER_NAME} module found and inserted" exit $? fi if [ -n "$ENABLE_DOWNLOAD" ]; then load_kernel_module_download fi + + if [ -n "$ENABLE_COMPILE" ]; then + load_kernel_module_compile + fi + + # Not able to download a prebuilt module nor to compile one on-the-fly + >&2 echo "Consider compiling your own ${DRIVER_NAME} driver and loading it or getting in touch with the Falco community" + exit 1 } clean_kernel_module() { @@ -278,30 +281,30 @@ clean_kernel_module() { fi KMOD_NAME=$(echo "${DRIVER_NAME}" | tr "-" "_") - if lsmod | cut -d' ' -f1 | grep -qx "${KMOD_NAME}"; then + if lsmod | cut -d' ' -f1 | grep -qx "${KMOD_NAME}"; then if rmmod "${DRIVER_NAME}" 2>/dev/null; then echo "* Unloading ${DRIVER_NAME} module succeeded" - else + else echo "* Unloading ${DRIVER_NAME} module failed" fi else - echo "* No ${DRIVER_NAME} module loaded" + echo "* There is no ${DRIVER_NAME} module loaded" fi - if ! hash dkms &>/dev/null; then + if ! hash dkms >/dev/null 2>&1; then echo "* Skipping dkms remove (dkms not found)" return fi - + DRIVER_VERSIONS=$(dkms status -m "${DRIVER_NAME}" | cut -d',' -f2 | sed -e 's/^[[:space:]]*//') if [ -z "${DRIVER_VERSIONS}" ]; then - echo "* No ${DRIVER_NAME} module found in dkms" + echo "* There is no ${DRIVER_NAME} module in dkms" return fi for CURRENT_VER in ${DRIVER_VERSIONS}; do if dkms remove -m "${DRIVER_NAME}" -v "${CURRENT_VER}" --all 2>/dev/null; then echo "* Removing ${DRIVER_NAME}/${CURRENT_VER} succeeded" - else + else echo "* Removing ${DRIVER_NAME}/${CURRENT_VER} failed" exit 1 fi @@ -314,14 +317,14 @@ load_bpf_probe_compile() { customize_kernel_build() { if [ -n "${KERNEL_EXTRA_VERSION}" ]; then - sed -i "s/LOCALVERSION=\"\"/LOCALVERSION=\"${KERNEL_EXTRA_VERSION}\"/" .config + sed -i "s/LOCALVERSION=\"\"/LOCALVERSION=\"${KERNEL_EXTRA_VERSION}\"/" .config fi make olddefconfig > /dev/null make modules_prepare > /dev/null } - if [ -n "${COS}" ]; then - echo "* COS detected (build ${BUILD_ID}), using cos kernel headers" + if [ "${TARGET_ID}" == "cos" ]; then + echo "* COS detected (build ${BUILD_ID}), using COS kernel headers" BPF_KERNEL_SOURCES_URL="https://storage.googleapis.com/cos-tools/${BUILD_ID}/kernel-headers.tgz" KERNEL_EXTRA_VERSION="+" @@ -352,7 +355,8 @@ load_bpf_probe_compile() { } fi - if [ -n "${MINIKUBE}" ]; then + if [ "${TARGET_ID}" == "minikube" ]; then + MINIKUBE_VERSION="$(cat "${HOST_ROOT}/etc/VERSION")" echo "* Minikube detected (${MINIKUBE_VERSION}), using linux kernel sources for minikube kernel" local kernel_version kernel_version=$(uname -r) @@ -378,14 +382,16 @@ load_bpf_probe_compile() { fi if [ -n "${BPF_KERNEL_SOURCES_URL}" ]; then + get_kernel_config + echo "* Downloading ${BPF_KERNEL_SOURCES_URL}" mkdir -p /tmp/kernel cd /tmp/kernel || exit cd "$(mktemp -d -p /tmp/kernel)" || exit if ! curl -L -o kernel-sources.tgz --create-dirs "${FALCO_DRIVER_CURL_OPTIONS}" "${BPF_KERNEL_SOURCES_URL}"; then - >&2 echo "Download failed" - exit 1; + >&2 echo "Unable to download the kernel sources" + return fi echo "* Extracting kernel sources" @@ -426,70 +432,46 @@ load_bpf_probe_download() { echo "* Trying to download a prebuilt eBPF probe from ${URL}" if ! curl -L --create-dirs "${FALCO_DRIVER_CURL_OPTIONS}" -o "${HOME}/.falco/${BPF_PROBE_FILENAME}" "${URL}"; then - >&2 echo "Download failed" - exit 1; + >&2 echo "Unable to find a prebuilt ${DRIVER_NAME} eBPF probe" + return fi } load_bpf_probe() { - echo "* Mounting debugfs" if [ ! -d /sys/kernel/debug/tracing ]; then mount -t debugfs nodev /sys/kernel/debug fi - get_kernel_config - - if [ -n "${HOST_ROOT}" ] && [ -f "${HOST_ROOT}/etc/os-release" ]; then - # shellcheck source=/dev/null - source "${HOST_ROOT}/etc/os-release" - - if [ "${ID}" == "cos" ]; then - COS=1 - fi - fi - - if [ -n "${HOST_ROOT}" ] && [ -f "${HOST_ROOT}/etc/VERSION" ]; then - MINIKUBE=1 - MINIKUBE_VERSION="$(cat "${HOST_ROOT}/etc/VERSION")" - fi - get_target_id BPF_PROBE_FILENAME="${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.o" - if [ -n "$ENABLE_COMPILE" ]; then + if [ -n "$ENABLE_DOWNLOAD" ]; then if [ -f "${HOME}/.falco/${BPF_PROBE_FILENAME}" ]; then - echo "* Skipping compile, eBPF probe is already present in ${HOME}/.falco/${BPF_PROBE_FILENAME}" + echo "* Skipping download, eBPF probe is already present in ${HOME}/.falco/${BPF_PROBE_FILENAME}" else - load_bpf_probe_compile + load_bpf_probe_download fi fi - if [ -n "$ENABLE_DOWNLOAD" ]; then + if [ -n "$ENABLE_COMPILE" ]; then if [ -f "${HOME}/.falco/${BPF_PROBE_FILENAME}" ]; then - echo "* Skipping download, eBPF probe is already present in ${HOME}/.falco/${BPF_PROBE_FILENAME}" + echo "* Skipping compilation, eBPF probe is already present in ${HOME}/.falco/${BPF_PROBE_FILENAME}" else - load_bpf_probe_download + load_bpf_probe_compile fi fi if [ -f "${HOME}/.falco/${BPF_PROBE_FILENAME}" ]; then echo "* eBPF probe located in ${HOME}/.falco/${BPF_PROBE_FILENAME}" - if [ ! -f /proc/sys/net/core/bpf_jit_enable ]; then - echo "******************************************************************" - echo "** BPF doesn't have JIT enabled, performance might be degraded. **" - echo "** Please ensure to run on a kernel with CONFIG_BPF_JIT on. **" - echo "******************************************************************" - fi - ln -sf "${HOME}/.falco/${BPF_PROBE_FILENAME}" "${HOME}/.falco/${DRIVER_NAME}-bpf.o" \ && echo "* Success: eBPF probe symlinked to ${HOME}/.falco/${DRIVER_NAME}-bpf.o" exit $? else - >&2 echo "Failure to find an eBPF probe" + >&2 echo "Unable to load the ${DRIVER_NAME} eBPF probe" exit 1 fi } @@ -506,13 +488,14 @@ print_usage() { echo "Options:" echo " --help show brief help" echo " --clean try to remove an already present driver installation" - echo " --compile try to compile the driver locally" - echo " --download try to download a prebuilt driver" + echo " --compile try to compile the driver locally (default true)" + echo " --download try to download a prebuilt driver (default true)" echo " --source-only skip execution and allow sourcing in another script" echo "" echo "Environment variables:" - echo " DRIVER_REPO specify a different URL where to look for prebuilt Falco drivers" - echo " DRIVER_NAME specify a different name for the driver" + echo " DRIVER_REPO specify a different URL where to look for prebuilt Falco drivers" + echo " DRIVER_NAME specify a different name for the driver" + echo " DRIVER_INSECURE_DOWNLOAD whether you want to allow insecure downloads or not" echo "" echo "Versions:" echo " Falco version ${FALCO_VERSION}" @@ -521,8 +504,15 @@ print_usage() { } ARCH=$(uname -m) + KERNEL_RELEASE=$(uname -r) + +if ! hash sed > /dev/null 2>&1; then + >&2 echo "This program requires sed" + exit 1 +fi KERNEL_VERSION=$(uname -v | sed 's/#\([[:digit:]]\+\).*/\1/') + DRIVERS_REPO=${DRIVERS_REPO:-"@DRIVERS_REPO@"} if [ -n "$DRIVER_INSECURE_DOWNLOAD" ] @@ -556,7 +546,7 @@ while test $# -gt 0; do case "$1" in module|bpf) if [ -n "$has_args" ]; then - >&2 echo "Only one driver can be passed" + >&2 echo "Only one driver per invocation" print_usage exit 1 else @@ -614,7 +604,7 @@ if [ -z "$source_only" ]; then fi if [ -n "$clean" ]; then - if ! [ -z "$has_opt"]; then + if [ -n "$has_opts" ]; then >&2 echo "Cannot use --clean with other options" exit 1 fi @@ -625,7 +615,7 @@ if [ -z "$source_only" ]; then clean_kernel_module ;; bpf) - >&2 echo "--clean not supported for driver=$DRIVER" + >&2 echo "--clean not supported for driver=bpf" exit 1 esac else