mirror of
https://github.com/falcosecurity/falco.git
synced 2025-08-01 14:37:49 +00:00
new falco-probe-loader file that doesn't depend on sysdig
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com> Co-authored-by: Leonardo Di Donato <leodidonato@gmail.com>
This commit is contained in:
parent
3b45e58217
commit
568f480942
411
scripts/falco-probe-loader
Executable file
411
scripts/falco-probe-loader
Executable file
@ -0,0 +1,411 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2013-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of sysdig .
|
||||
#
|
||||
# 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 sysdig-probe looking
|
||||
# for it in a bunch of ways. Convenient when running sysdig 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 [ ! -z "${SYSDIG_HOST_ROOT}" ] && [ -f "${SYSDIG_HOST_ROOT}/boot/config-${KERNEL_RELEASE}" ]; then
|
||||
echo "Found kernel config at ${SYSDIG_HOST_ROOT}/boot/config-${KERNEL_RELEASE}"
|
||||
KERNEL_CONFIG_PATH="${SYSDIG_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 [ ! -z "${SYSDIG_HOST_ROOT}" ] && [ -f "${SYSDIG_HOST_ROOT}/usr/lib/ostree-boot/config-${KERNEL_RELEASE}" ]; then
|
||||
echo "Found kernel config at ${SYSDIG_HOST_ROOT}/usr/lib/ostree-boot/config-${KERNEL_RELEASE}"
|
||||
KERNEL_CONFIG_PATH="${SYSDIG_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
|
||||
# Dockerfile sets up the desired symlink /lib/modules -> $SYSDIG_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
|
||||
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
|
||||
}
|
||||
|
||||
load_kernel_probe() {
|
||||
if ! hash lsmod > /dev/null 2>&1; then
|
||||
echo "This program requires lsmod"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! hash modprobe > /dev/null 2>&1; then
|
||||
echo "This program requires modprobe"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! hash rmmod > /dev/null 2>&1; then
|
||||
echo "This program requires rmmod"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "* Unloading ${PROBE_NAME}, if present"
|
||||
rmmod "${PROBE_NAME}" 2>/dev/null
|
||||
WAIT_TIME=0
|
||||
KMOD_NAME=$(echo "${PROBE_NAME}" | tr "-" "_")
|
||||
while lsmod | grep "${KMOD_NAME}" > /dev/null 2>&1 && [ $WAIT_TIME -lt $MAX_RMMOD_WAIT ]; do
|
||||
if rmmod "${PROBE_NAME}" 2>/dev/null; then
|
||||
echo "* Unloading ${PROBE_NAME} succeeded after ${WAIT_TIME}s"
|
||||
break
|
||||
fi
|
||||
((++WAIT_TIME))
|
||||
if (( $WAIT_TIME % 5 == 0 )); then
|
||||
echo "* ${PROBE_NAME} still loaded, waited ${WAIT_TIME}s (max wait ${MAX_RMMOD_WAIT}s)"
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if lsmod | grep "${KMOD_NAME}" > /dev/null 2>&1; then
|
||||
echo "* ${PROBE_NAME} seems to still be loaded, hoping the best"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# skip dkms on UEK hosts because it will always fail
|
||||
if [[ $(uname -r) == *uek* ]]; then
|
||||
echo "* Skipping dkms install for UEK host"
|
||||
else
|
||||
echo "* Running dkms install for ${PACKAGE_NAME}"
|
||||
if dkms install -m "${PACKAGE_NAME}" -v "${SYSDIG_VERSION}" -k "${KERNEL_RELEASE}"; then
|
||||
echo "* Trying to load a dkms ${PROBE_NAME}, if present"
|
||||
|
||||
if insmod "/var/lib/dkms/${PACKAGE_NAME}/${SYSDIG_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${PROBE_NAME}.ko" > /dev/null 2>&1; then
|
||||
echo "${PROBE_NAME} found and loaded in dkms"
|
||||
exit 0
|
||||
elif insmod "/var/lib/dkms/${PACKAGE_NAME}/${SYSDIG_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${PROBE_NAME}.ko.xz" > /dev/null 2>&1; then
|
||||
echo "${PROBE_NAME} found and loaded in dkms (xz)"
|
||||
exit 0
|
||||
else
|
||||
echo "* Unable to insmod"
|
||||
fi
|
||||
else
|
||||
DKMS_LOG="/var/lib/dkms/${PACKAGE_NAME}/${SYSDIG_VERSION}/build/make.log"
|
||||
if [ -f "${DKMS_LOG}" ]; then
|
||||
echo "* Running dkms build failed, dumping ${DKMS_LOG}"
|
||||
cat "${DKMS_LOG}"
|
||||
else
|
||||
echo "* Running dkms build failed, couldn't find ${DKMS_LOG}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "* Trying to load a system ${PROBE_NAME}, if present"
|
||||
|
||||
if modprobe "${PROBE_NAME}" > /dev/null 2>&1; then
|
||||
echo "${PROBE_NAME} found and loaded with modprobe"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "* Trying to find precompiled ${PROBE_NAME} for ${KERNEL_RELEASE}"
|
||||
|
||||
get_kernel_config
|
||||
|
||||
local SYSDIG_PROBE_FILENAME="${PROBE_NAME}-${SYSDIG_VERSION}-${ARCH}-${KERNEL_RELEASE}-${HASH}.ko"
|
||||
|
||||
if [ -f "${HOME}/.sysdig/${SYSDIG_PROBE_FILENAME}" ]; then
|
||||
echo "Found precompiled module at ~/.sysdig/${SYSDIG_PROBE_FILENAME}, loading module"
|
||||
insmod "${HOME}/.sysdig/${SYSDIG_PROBE_FILENAME}"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
local URL
|
||||
URL=$(echo "${SYSDIG_PROBE_URL}/${SYSDIG_REPOSITORY}/sysdig-probe-binaries/${SYSDIG_PROBE_FILENAME}" | sed s/+/%2B/g)
|
||||
|
||||
echo "* Trying to download precompiled module from ${URL}"
|
||||
if curl --create-dirs "${SYSDIG_PROBE_CURL_OPTIONS}" -o "${HOME}/.sysdig/${SYSDIG_PROBE_FILENAME}" "${URL}"; then
|
||||
echo "Download succeeded, loading module"
|
||||
insmod "${HOME}/.sysdig/${SYSDIG_PROBE_FILENAME}"
|
||||
exit $?
|
||||
else
|
||||
echo "Download failed, consider compiling your own ${PROBE_NAME} and loading it or getting in touch with the sysdig community"
|
||||
exit 1
|
||||
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 [ ! -z "${SYSDIG_HOST_ROOT}" ] && [ -f "${SYSDIG_HOST_ROOT}/etc/os-release" ]; then
|
||||
. "${SYSDIG_HOST_ROOT}/etc/os-release"
|
||||
|
||||
if [ "${ID}" == "cos" ]; then
|
||||
COS=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "${SYSDIG_HOST_ROOT}" ] && [ -f "${SYSDIG_HOST_ROOT}/etc/VERSION" ]; then
|
||||
MINIKUBE=1
|
||||
MINIKUBE_VERSION="$(cat ${SYSDIG_HOST_ROOT}/etc/VERSION)"
|
||||
fi
|
||||
|
||||
local BPF_PROBE_FILENAME="${BPF_PROBE_NAME}-${SYSDIG_VERSION}-${ARCH}-${KERNEL_RELEASE}-${HASH}.o"
|
||||
|
||||
if [ ! -f "${HOME}/.sysdig/${BPF_PROBE_FILENAME}" ]; then
|
||||
|
||||
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 [ -n "${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
|
||||
|
||||
# Note: this overrides the KERNELDIR set while untarring the tarball
|
||||
export KERNELDIR=`pwd`
|
||||
|
||||
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
|
||||
|
||||
# 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 [ -n "${MINIKUBE}" ]; then
|
||||
echo "* Minikube detected (${MINIKUBE_VERSION}), using linux kernel sources for minikube kernel"
|
||||
local 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 "${SYSDIG_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
|
||||
echo "* Downloading ${BPF_KERNEL_SOURCES_URL}"
|
||||
|
||||
mkdir -p /tmp/kernel
|
||||
cd /tmp/kernel
|
||||
cd `mktemp -d -p /tmp/kernel`
|
||||
if ! curl -o kernel-sources.tgz --create-dirs "${SYSDIG_PROBE_CURL_OPTIONS}" "${BPF_KERNEL_SOURCES_URL}"; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
echo "* Extracting kernel sources"
|
||||
|
||||
mkdir kernel-sources && tar xf kernel-sources.tgz -C kernel-sources --strip-components "${STRIP_COMPONENTS}"
|
||||
|
||||
cd kernel-sources
|
||||
export KERNELDIR=`pwd`
|
||||
|
||||
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 BPF probe ${BPF_PROBE_NAME} (${BPF_PROBE_FILENAME})"
|
||||
|
||||
make -C "/usr/src/${PACKAGE_NAME}-${SYSDIG_VERSION}/bpf" > /dev/null
|
||||
|
||||
mkdir -p ~/.sysdig
|
||||
mv "/usr/src/${PACKAGE_NAME}-${SYSDIG_VERSION}/bpf/probe.o" "${HOME}/.sysdig/${BPF_PROBE_FILENAME}"
|
||||
|
||||
if [ -n "${BPF_KERNEL_SOURCES_URL}" ]; then
|
||||
rm -r /tmp/kernel
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f "${HOME}/.sysdig/${BPF_PROBE_FILENAME}" ]; then
|
||||
local URL
|
||||
URL=$(echo "${SYSDIG_PROBE_URL}/${SYSDIG_REPOSITORY}/sysdig-probe-binaries/${BPF_PROBE_FILENAME}" | sed s/+/%2B/g)
|
||||
|
||||
echo "* Trying to download precompiled BPF probe from ${URL}"
|
||||
|
||||
curl --create-dirs "${SYSDIG_PROBE_CURL_OPTIONS}" -o "${HOME}/.sysdig/${BPF_PROBE_FILENAME}" "${URL}"
|
||||
fi
|
||||
|
||||
if [ -f "${HOME}/.sysdig/${BPF_PROBE_FILENAME}" ]; then
|
||||
if [ ! -f /proc/sys/net/core/bpf_jit_enable ]; then
|
||||
echo "**********************************************************"
|
||||
echo "** BPF doesn't have JIT enabled, performance might be **"
|
||||
echo "** degraded. Please ensure to run on a kernel with **"
|
||||
echo "** CONFIG_BPF_JIT enabled and/or use --net=host if **"
|
||||
echo "** running inside a container. **"
|
||||
echo "**********************************************************"
|
||||
fi
|
||||
|
||||
echo "* BPF probe located, it's now possible to start sysdig"
|
||||
|
||||
ln -sf "${HOME}/.sysdig/${BPF_PROBE_FILENAME}" "${HOME}/.sysdig/${BPF_PROBE_NAME}.o"
|
||||
exit $?
|
||||
else
|
||||
echo "* Failure to find a BPF probe"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
ARCH=$(uname -m)
|
||||
KERNEL_RELEASE=$(uname -r)
|
||||
SCRIPT_NAME=$(basename "${0}")
|
||||
SYSDIG_PROBE_URL=${SYSDIG_PROBE_URL:-https://s3.amazonaws.com/download.draios.com}
|
||||
if [ -n "$SYSDIG_PROBE_INSECURE_DOWNLOAD" ]
|
||||
then
|
||||
SYSDIG_PROBE_CURL_OPTIONS=-fsSk
|
||||
else
|
||||
SYSDIG_PROBE_CURL_OPTIONS=-fsS
|
||||
fi
|
||||
|
||||
MAX_RMMOD_WAIT=60
|
||||
if [[ $# -ge 1 ]]; then
|
||||
MAX_RMMOD_WAIT=$1
|
||||
fi
|
||||
|
||||
if [ -z "${SYSDIG_REPOSITORY}" ]; then
|
||||
SYSDIG_REPOSITORY="stable"
|
||||
fi
|
||||
|
||||
if [ "${SCRIPT_NAME}" = "falco-probe-loader" ]; then
|
||||
if [ -z "$SYSDIG_VERSION" ]; then
|
||||
SYSDIG_VERSION=$(falco --version | cut -d' ' -f3)
|
||||
fi
|
||||
PROBE_NAME="falco-probe"
|
||||
BPF_PROBE_NAME="falco-probe-bpf"
|
||||
PACKAGE_NAME="falco"
|
||||
else
|
||||
echo "This script must be called as falco-probe-loader"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" != 0 ]; then
|
||||
echo "Installer must be run as root (or with sudo)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! hash curl > /dev/null 2>&1; then
|
||||
echo "This program requires curl"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -v SYSDIG_BPF_PROBE ] || [ "${1}" = "bpf" ]; then
|
||||
load_bpf_probe
|
||||
else
|
||||
load_kernel_probe
|
||||
fi
|
Loading…
Reference in New Issue
Block a user