mirror of
https://github.com/falcosecurity/falco.git
synced 2026-01-30 14:08:21 +00:00
This is needed in systems where raw tracepoints are not available. Anyways, since this is needed when the inspector open (and actually loads) the eBPF probe, ideally the mount should not be done by this script but rather from Falco, or from Falco libs. Otherwise, users building the eBPF probe theirseleves and not using this script (and having a kernel without raw tracepoints) may need to mount this fs theirselves. Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
637 lines
18 KiB
Bash
Executable File
637 lines
18 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Copyright (C) 2021 The Falco Authors.
|
|
#
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# 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
|
|
# a container or in other weird environments.
|
|
#
|
|
|
|
#
|
|
# Returns 1 if $cos_ver > $base_ver, 0 otherwise
|
|
#
|
|
cos_version_greater() {
|
|
if [[ $cos_ver == "${base_ver}" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
#
|
|
# COS build numbers are in the format x.y.z
|
|
#
|
|
a=$(echo "${cos_ver}" | cut -d. -f1)
|
|
b=$(echo "${cos_ver}" | cut -d. -f2)
|
|
c=$(echo "${cos_ver}" | cut -d. -f3)
|
|
|
|
d=$(echo "${base_ver}" | cut -d. -f1)
|
|
e=$(echo "${base_ver}" | cut -d. -f2)
|
|
f=$(echo "${base_ver}" | cut -d. -f3)
|
|
|
|
# Test the first component
|
|
if [[ $a -gt $d ]]; then
|
|
return 1
|
|
elif [[ $d -gt $a ]]; then
|
|
return 0
|
|
fi
|
|
|
|
# Test the second component
|
|
if [[ $b -gt $e ]]; then
|
|
return 1
|
|
elif [[ $e -gt $b ]]; then
|
|
return 0
|
|
fi
|
|
|
|
# Test the third component
|
|
if [[ $c -gt $f ]]; then
|
|
return 1
|
|
elif [[ $f -gt $c ]]; then
|
|
return 0
|
|
fi
|
|
|
|
# If we get here, probably malformatted version string?
|
|
|
|
return 0
|
|
}
|
|
|
|
get_kernel_config() {
|
|
if [ -f /proc/config.gz ]; then
|
|
echo "* Found kernel config at /proc/config.gz"
|
|
KERNEL_CONFIG_PATH=/proc/config.gz
|
|
elif [ -f "/boot/config-${KERNEL_RELEASE}" ]; then
|
|
echo "* Found kernel config at /boot/config-${KERNEL_RELEASE}"
|
|
KERNEL_CONFIG_PATH=/boot/config-${KERNEL_RELEASE}
|
|
elif [ -n "${HOST_ROOT}" ] && [ -f "${HOST_ROOT}/boot/config-${KERNEL_RELEASE}" ]; then
|
|
echo "* Found kernel config at ${HOST_ROOT}/boot/config-${KERNEL_RELEASE}"
|
|
KERNEL_CONFIG_PATH="${HOST_ROOT}/boot/config-${KERNEL_RELEASE}"
|
|
elif [ -f "/usr/lib/ostree-boot/config-${KERNEL_RELEASE}" ]; then
|
|
echo "* Found kernel config at /usr/lib/ostree-boot/config-${KERNEL_RELEASE}"
|
|
KERNEL_CONFIG_PATH="/usr/lib/ostree-boot/config-${KERNEL_RELEASE}"
|
|
elif [ -n "${HOST_ROOT}" ] && [ -f "${HOST_ROOT}/usr/lib/ostree-boot/config-${KERNEL_RELEASE}" ]; then
|
|
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 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"
|
|
fi
|
|
|
|
if [ -z "${KERNEL_CONFIG_PATH}" ]; then
|
|
>&2 echo "Cannot find kernel config"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${KERNEL_CONFIG_PATH}" == *.gz ]]; then
|
|
HASH=$(zcat "${KERNEL_CONFIG_PATH}" | md5sum - | cut -d' ' -f1)
|
|
else
|
|
HASH=$(md5sum "${KERNEL_CONFIG_PATH}" | cut -d' ' -f1)
|
|
fi
|
|
}
|
|
|
|
get_target_id() {
|
|
if [ -f "${HOST_ROOT}/etc/os-release" ]; then
|
|
# freedesktop.org and systemd
|
|
# shellcheck source=/dev/null
|
|
source "${HOST_ROOT}/etc/os-release"
|
|
OS_ID=$ID
|
|
elif [ -f "${HOST_ROOT}/etc/debian_version" ]; then
|
|
# Older debian distros
|
|
# fixme > Can this happen on older Ubuntu?
|
|
OS_ID=debian
|
|
elif [ -f "${HOST_ROOT}/etc/centos-release" ]; then
|
|
# 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
|
|
fi
|
|
|
|
case "${OS_ID}" in
|
|
("amzn")
|
|
if [[ $VERSION_ID == "2" ]]; then
|
|
TARGET_ID="amazonlinux2"
|
|
else
|
|
TARGET_ID="amazonlinux"
|
|
fi
|
|
;;
|
|
("ubuntu")
|
|
if [[ $KERNEL_RELEASE == *"aws"* ]]; then
|
|
TARGET_ID="ubuntu-aws"
|
|
else
|
|
TARGET_ID="ubuntu-generic"
|
|
fi
|
|
;;
|
|
(*)
|
|
TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]')
|
|
;;
|
|
esac
|
|
}
|
|
|
|
load_kernel_module_compile() {
|
|
# Skip dkms on UEK hosts because it will always fail
|
|
if [[ $(uname -r) == *uek* ]]; then
|
|
>&2 echo "Skipping because the dkms install always fail (on UEK hosts)"
|
|
return
|
|
fi
|
|
|
|
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
|
|
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
|
|
echo "make CC=${CURRENT_GCC} \$@" >> /tmp/falco-dkms-make
|
|
chmod +x /tmp/falco-dkms-make
|
|
if dkms install --directive="MAKE='/tmp/falco-dkms-make'" -m "${DRIVER_NAME}" -v "${DRIVER_VERSION}" -k "${KERNEL_RELEASE}" 2>/dev/null; then
|
|
echo "* ${DRIVER_NAME} module installed in dkms, trying to insmod"
|
|
if insmod "/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${DRIVER_NAME}.ko" > /dev/null 2>&1; then
|
|
echo "* Success: ${DRIVER_NAME} module found and loaded in dkms"
|
|
exit 0
|
|
elif insmod "/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${DRIVER_NAME}.ko.xz" > /dev/null 2>&1; then
|
|
echo "* Success: ${DRIVER_NAME} module found and loaded in dkms (xz)"
|
|
exit 0
|
|
else
|
|
echo "* Unable to insmod ${DRIVER_NAME} module"
|
|
fi
|
|
else
|
|
DKMS_LOG="/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/build/make.log"
|
|
if [ -f "${DKMS_LOG}" ]; then
|
|
echo "* Running dkms build failed, dumping ${DKMS_LOG} (with GCC ${CURRENT_GCC})"
|
|
cat "${DKMS_LOG}"
|
|
else
|
|
echo "* Running dkms build failed, couldn't find ${DKMS_LOG} (with GCC ${CURRENT_GCC})"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
load_kernel_module_download() {
|
|
get_target_id
|
|
|
|
local FALCO_KERNEL_MODULE_FILENAME="${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.ko"
|
|
|
|
local URL
|
|
URL=$(echo "${DRIVERS_REPO}/${DRIVER_VERSION}/${FALCO_KERNEL_MODULE_FILENAME}" | sed s/+/%2B/g)
|
|
|
|
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 found and inserted"
|
|
exit $?
|
|
else
|
|
>&2 echo "Unable to find a prebuilt ${DRIVER_NAME} module"
|
|
return
|
|
fi
|
|
}
|
|
|
|
load_kernel_module() {
|
|
if ! hash lsmod > /dev/null 2>&1; then
|
|
>&2 echo "This program requires lsmod"
|
|
exit 1
|
|
fi
|
|
|
|
if ! hash modprobe > /dev/null 2>&1; then
|
|
>&2 echo "This program requires modprobe"
|
|
exit 1
|
|
fi
|
|
|
|
if ! hash rmmod > /dev/null 2>&1; then
|
|
>&2 echo "This program requires rmmod"
|
|
exit 1
|
|
fi
|
|
|
|
echo "* Unloading ${DRIVER_NAME} module, if present"
|
|
rmmod "${DRIVER_NAME}" 2>/dev/null
|
|
WAIT_TIME=0
|
|
KMOD_NAME=$(echo "${DRIVER_NAME}" | tr "-" "_")
|
|
while lsmod | cut -d' ' -f1 | grep -qx "${KMOD_NAME}" && [ $WAIT_TIME -lt "${MAX_RMMOD_WAIT}" ]; do
|
|
if rmmod "${DRIVER_NAME}" 2>/dev/null; then
|
|
echo "* Unloading ${DRIVER_NAME} module succeeded after ${WAIT_TIME}s"
|
|
break
|
|
fi
|
|
((++WAIT_TIME))
|
|
if (( WAIT_TIME % 5 == 0 )); then
|
|
echo "* ${DRIVER_NAME} module still loaded, waited ${WAIT_TIME}s (max wait ${MAX_RMMOD_WAIT}s)"
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
if lsmod | cut -d' ' -f1 | grep -qx "${KMOD_NAME}" > /dev/null 2>&1; then
|
|
echo "* ${DRIVER_NAME} module seems to still be loaded, hoping the best"
|
|
exit 0
|
|
fi
|
|
|
|
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 "* 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 ${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() {
|
|
if ! hash lsmod > /dev/null 2>&1; then
|
|
>&2 echo "This program requires lsmod"
|
|
exit 1
|
|
fi
|
|
|
|
if ! hash rmmod > /dev/null 2>&1; then
|
|
>&2 echo "This program requires rmmod"
|
|
exit 1
|
|
fi
|
|
|
|
KMOD_NAME=$(echo "${DRIVER_NAME}" | tr "-" "_")
|
|
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
|
|
echo "* Unloading ${DRIVER_NAME} module failed"
|
|
fi
|
|
else
|
|
echo "* There is no ${DRIVER_NAME} module loaded"
|
|
fi
|
|
|
|
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 "* 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
|
|
echo "* Removing ${DRIVER_NAME}/${CURRENT_VER} failed"
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
load_bpf_probe_compile() {
|
|
local BPF_KERNEL_SOURCES_URL=""
|
|
local STRIP_COMPONENTS=1
|
|
|
|
customize_kernel_build() {
|
|
if [ -n "${KERNEL_EXTRA_VERSION}" ]; then
|
|
sed -i "s/LOCALVERSION=\"\"/LOCALVERSION=\"${KERNEL_EXTRA_VERSION}\"/" .config
|
|
fi
|
|
make olddefconfig > /dev/null
|
|
make modules_prepare > /dev/null
|
|
}
|
|
|
|
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="+"
|
|
STRIP_COMPONENTS=0
|
|
|
|
customize_kernel_build() {
|
|
pushd usr/src/* > /dev/null || exit
|
|
|
|
# Note: this overrides the KERNELDIR set while untarring the tarball
|
|
KERNELDIR=$(pwd)
|
|
export KERNELDIR
|
|
|
|
sed -i '/^#define randomized_struct_fields_start struct {$/d' include/linux/compiler-clang.h
|
|
sed -i '/^#define randomized_struct_fields_end };$/d' include/linux/compiler-clang.h
|
|
|
|
popd > /dev/null || exit
|
|
|
|
# Might need to configure our own sources depending on COS version
|
|
cos_ver=${BUILD_ID}
|
|
base_ver=11553.0.0
|
|
|
|
cos_version_greater
|
|
greater_ret=$?
|
|
|
|
if [[ greater_ret -eq 1 ]]; then
|
|
export KBUILD_EXTRA_CPPFLAGS=-DCOS_73_WORKAROUND
|
|
fi
|
|
}
|
|
fi
|
|
|
|
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)
|
|
local -r kernel_version_major=$(echo "${kernel_version}" | cut -d. -f1)
|
|
local -r kernel_version_minor=$(echo "${kernel_version}" | cut -d. -f2)
|
|
local -r kernel_version_patch=$(echo "${kernel_version}" | cut -d. -f3)
|
|
|
|
if [ "${kernel_version_patch}" == "0" ]; then
|
|
kernel_version="${kernel_version_major}.${kernel_version_minor}"
|
|
fi
|
|
|
|
BPF_KERNEL_SOURCES_URL="http://mirrors.edge.kernel.org/pub/linux/kernel/v${kernel_version_major}.x/linux-${kernel_version}.tar.gz"
|
|
fi
|
|
|
|
if [ -n "${BPF_USE_LOCAL_KERNEL_SOURCES}" ]; then
|
|
local -r kernel_version_major=$(uname -r | cut -d. -f1)
|
|
local -r kernel_version=$(uname -r | cut -d- -f1)
|
|
KERNEL_EXTRA_VERSION="-$(uname -r | cut -d- -f2)"
|
|
|
|
echo "* Using downloaded kernel sources for kernel version ${kernel_version}..."
|
|
|
|
BPF_KERNEL_SOURCES_URL="http://mirrors.edge.kernel.org/pub/linux/kernel/v${kernel_version_major}.x/linux-${kernel_version}.tar.gz"
|
|
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 "Unable to download the kernel sources"
|
|
return
|
|
fi
|
|
|
|
echo "* Extracting kernel sources"
|
|
|
|
mkdir kernel-sources && tar xf kernel-sources.tgz -C kernel-sources --strip-components "${STRIP_COMPONENTS}"
|
|
|
|
cd kernel-sources || exit
|
|
KERNELDIR=$(pwd)
|
|
export KERNELDIR
|
|
|
|
if [[ "${KERNEL_CONFIG_PATH}" == *.gz ]]; then
|
|
zcat "${KERNEL_CONFIG_PATH}" > .config
|
|
else
|
|
cat "${KERNEL_CONFIG_PATH}" > .config
|
|
fi
|
|
|
|
echo "* Configuring kernel"
|
|
customize_kernel_build
|
|
fi
|
|
|
|
echo "* Trying to compile the eBPF probe (${BPF_PROBE_FILENAME})"
|
|
|
|
make -C "/usr/src/${DRIVER_NAME}-${DRIVER_VERSION}/bpf" > /dev/null
|
|
|
|
mkdir -p "${HOME}/.falco"
|
|
mv "/usr/src/${DRIVER_NAME}-${DRIVER_VERSION}/bpf/probe.o" "${HOME}/.falco/${BPF_PROBE_FILENAME}"
|
|
|
|
if [ -n "${BPF_KERNEL_SOURCES_URL}" ]; then
|
|
rm -r /tmp/kernel
|
|
fi
|
|
|
|
}
|
|
|
|
load_bpf_probe_download() {
|
|
local URL
|
|
URL=$(echo "${DRIVERS_REPO}/${DRIVER_VERSION}/${BPF_PROBE_FILENAME}" | sed s/+/%2B/g)
|
|
|
|
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 "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_target_id
|
|
|
|
BPF_PROBE_FILENAME="${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.o"
|
|
|
|
if [ -n "$ENABLE_DOWNLOAD" ]; then
|
|
if [ -f "${HOME}/.falco/${BPF_PROBE_FILENAME}" ]; then
|
|
echo "* Skipping download, eBPF probe is already present in ${HOME}/.falco/${BPF_PROBE_FILENAME}"
|
|
else
|
|
load_bpf_probe_download
|
|
fi
|
|
fi
|
|
|
|
if [ -n "$ENABLE_COMPILE" ]; then
|
|
if [ -f "${HOME}/.falco/${BPF_PROBE_FILENAME}" ]; then
|
|
echo "* Skipping compilation, eBPF probe is already present in ${HOME}/.falco/${BPF_PROBE_FILENAME}"
|
|
else
|
|
load_bpf_probe_compile
|
|
fi
|
|
fi
|
|
|
|
if [ -f "${HOME}/.falco/${BPF_PROBE_FILENAME}" ]; then
|
|
echo "* eBPF probe located in ${HOME}/.falco/${BPF_PROBE_FILENAME}"
|
|
|
|
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 "Unable to load the ${DRIVER_NAME} eBPF probe"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
print_usage() {
|
|
echo ""
|
|
echo "Usage:"
|
|
echo " falco-driver-loader [driver] [options]"
|
|
echo ""
|
|
echo "Available drivers:"
|
|
echo " module kernel module (default)"
|
|
echo " bpf eBPF probe"
|
|
echo ""
|
|
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 (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_INSECURE_DOWNLOAD whether you want to allow insecure downloads or not"
|
|
echo ""
|
|
echo "Versions:"
|
|
echo " Falco version ${FALCO_VERSION}"
|
|
echo " Driver version ${DRIVER_VERSION}"
|
|
echo ""
|
|
}
|
|
|
|
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" ]
|
|
then
|
|
FALCO_DRIVER_CURL_OPTIONS=-fsSk
|
|
else
|
|
FALCO_DRIVER_CURL_OPTIONS=-fsS
|
|
fi
|
|
|
|
if [[ -z "$MAX_RMMOD_WAIT" ]]; then
|
|
MAX_RMMOD_WAIT=60
|
|
fi
|
|
|
|
DRIVER_VERSION="@PROBE_VERSION@"
|
|
DRIVER_NAME=${DRIVER_NAME:-"@PROBE_NAME@"}
|
|
FALCO_VERSION="@FALCO_VERSION@"
|
|
|
|
DRIVER="module"
|
|
if [ -v FALCO_BPF_PROBE ]; then
|
|
DRIVER="bpf"
|
|
fi
|
|
|
|
ENABLE_COMPILE=
|
|
ENABLE_DOWNLOAD=
|
|
|
|
clean=
|
|
has_args=
|
|
has_opts=
|
|
source_only=
|
|
while test $# -gt 0; do
|
|
case "$1" in
|
|
module|bpf)
|
|
if [ -n "$has_args" ]; then
|
|
>&2 echo "Only one driver per invocation"
|
|
print_usage
|
|
exit 1
|
|
else
|
|
DRIVER="$1"
|
|
has_args="true"
|
|
shift
|
|
fi
|
|
;;
|
|
-h|--help)
|
|
print_usage
|
|
exit 0
|
|
;;
|
|
--clean)
|
|
clean="true"
|
|
shift
|
|
;;
|
|
--compile)
|
|
ENABLE_COMPILE="yes"
|
|
has_opts="true"
|
|
shift
|
|
;;
|
|
--download)
|
|
ENABLE_DOWNLOAD="yes"
|
|
has_opts="true"
|
|
shift
|
|
;;
|
|
--source-only)
|
|
source_only="true"
|
|
shift
|
|
;;
|
|
--*)
|
|
>&2 echo "Unknown option: $1"
|
|
print_usage
|
|
exit 1
|
|
;;
|
|
*)
|
|
>&2 echo "Unknown driver: $1"
|
|
print_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$has_opts" ]; then
|
|
ENABLE_COMPILE="yes"
|
|
ENABLE_DOWNLOAD="yes"
|
|
fi
|
|
|
|
if [ -z "$source_only" ]; then
|
|
echo "* Running falco-driver-loader for: falco version=${FALCO_VERSION}, driver version=${DRIVER_VERSION}"
|
|
|
|
if [ "$(id -u)" != 0 ]; then
|
|
>&2 echo "This program must be run as root (or with sudo)"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -n "$clean" ]; then
|
|
if [ -n "$has_opts" ]; then
|
|
>&2 echo "Cannot use --clean with other options"
|
|
exit 1
|
|
fi
|
|
|
|
echo "* Running falco-driver-loader with: driver=$DRIVER, clean=yes"
|
|
case $DRIVER in
|
|
module)
|
|
clean_kernel_module
|
|
;;
|
|
bpf)
|
|
>&2 echo "--clean not supported for driver=bpf"
|
|
exit 1
|
|
esac
|
|
else
|
|
if ! hash curl > /dev/null 2>&1; then
|
|
>&2 echo "This program requires curl"
|
|
exit 1
|
|
fi
|
|
|
|
echo "* Running falco-driver-loader with: driver=$DRIVER, compile=${ENABLE_COMPILE:-"no"}, download=${ENABLE_DOWNLOAD:-"no"}"
|
|
case $DRIVER in
|
|
module)
|
|
load_kernel_module
|
|
;;
|
|
bpf)
|
|
load_bpf_probe
|
|
;;
|
|
esac
|
|
fi
|
|
fi |