Skip to content

Commit

Permalink
feat: check cap privileges instead of Geteuid during starting the a…
Browse files Browse the repository at this point in the history
…gent (#242)

* feat: Introduce github.com/containerd/containerd/pkg/cap to check whether process has CAP_BPF privilege

Signed-off-by: spencercjh <[email protected]>

* fix: better logs

* fix: adapt to e2e test env

* style: go mod tidy

* fix: make tests pass

* fix: DO NOT use containerd cap package

* test: introduce tests to verify agent/common/permission.go

* fix: correct implementation refer to https://man7.org/linux/man-pages/man2/capset.2.html

* test: test test_add_cap_bpf first

* test: cap-add difference capability for different kernal

* test: load btf file to container and run kyanos with --btf flag

* test: add missing capability CAP_SYS_RESOURCE

* test: try to use --privileged instead of cap-add

---------

Signed-off-by: spencercjh <[email protected]>
  • Loading branch information
spencercjh authored Jan 3, 2025
1 parent ca70f6d commit 6d0b142
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 33 deletions.
83 changes: 55 additions & 28 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,33 @@ jobs:
#install python pip
sudo apt install -y python3 python3-pip pipx
- name: Test CAP_BPF privilege check
uses: cilium/little-vm-helper@97c89f004bd0ab4caeacfe92ebc956e13e362e6b # v0.0.19
if: ${{ !contains(fromJSON('["4.19-20240912.022020", "5.4-20240912.022020"]'), matrix.kernel) }}
with:
provision: 'false'
cmd: |
set -euxo pipefail
uname -a
cat /etc/issue
pushd /host
bash /host/testdata/run_cap_bpf_test.sh "" "CAP_BPF"
popd
- name: Test CAP_SYS_ADMIN privilege check
uses: cilium/little-vm-helper@97c89f004bd0ab4caeacfe92ebc956e13e362e6b # v0.0.19
if: contains(fromJSON('["4.19-20240912.022020", "5.4-20240912.022020"]'), matrix.kernel)
with:
provision: 'false'
cmd: |
set -euxo pipefail
uname -a
cat /etc/issue
pushd /host
bash /host/testdata/run_cap_bpf_test.sh "" "CAP_SYS_ADMIN"
popd
- name: Test filter by comm
uses: cilium/little-vm-helper@97c89f004bd0ab4caeacfe92ebc956e13e362e6b # v0.0.19
with:
Expand All @@ -165,9 +192,9 @@ jobs:
cat /etc/issue
pushd /host
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_filter_by_comm.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_filter_by_comm.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_filter_by_comm.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_filter_by_comm.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
popd
Expand All @@ -181,9 +208,9 @@ jobs:
cat /etc/issue
pushd /host
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_gotls.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_gotls.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_gotls.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_gotls.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
popd
Expand All @@ -197,9 +224,9 @@ jobs:
cat /etc/issue
pushd /host
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_https.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_https.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_https.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_https.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
popd
Expand All @@ -213,9 +240,9 @@ jobs:
cat /etc/issue
pushd /host
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_side.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_side.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_side.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_side.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
popd
Expand All @@ -229,9 +256,9 @@ jobs:
cat /etc/issue
pushd /host
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_mysql.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_mysql.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_mysql.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_mysql.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
popd
Expand All @@ -244,9 +271,9 @@ jobs:
uname -a
cat /etc/issue
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_base.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_base.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_base.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_base.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
Expand All @@ -259,9 +286,9 @@ jobs:
uname -a
cat /etc/issue
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_filter_by_l4.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_filter_by_l4.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_filter_by_l4.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_filter_by_l4.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
- name: Test kern evt
Expand All @@ -273,9 +300,9 @@ jobs:
uname -a
cat /etc/issue
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_kern_evt.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_kern_evt.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_kern_evt.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_kern_evt.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
- name: Test test docker filter by container id
Expand All @@ -287,9 +314,9 @@ jobs:
uname -a
cat /etc/issue
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_docker_filter_by_container_id.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_docker_filter_by_container_id.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_docker_filter_by_container_id.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_docker_filter_by_container_id.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
- name: Test test docker filter by container name
Expand All @@ -301,9 +328,9 @@ jobs:
uname -a
cat /etc/issue
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_docker_filter_by_container_name.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_docker_filter_by_container_name.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_docker_filter_by_container_name.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_docker_filter_by_container_name.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
- name: Test filter by pid
Expand All @@ -315,9 +342,9 @@ jobs:
uname -a
cat /etc/issue
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_docker_filter_by_pid.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_docker_filter_by_pid.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_docker_filter_by_pid.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_docker_filter_by_pid.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
- name: Test test containerd filter by container name
Expand All @@ -329,9 +356,9 @@ jobs:
uname -a
cat /etc/issue
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_containerd_filter_by_container_name.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_containerd_filter_by_container_name.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_containerd_filter_by_container_name.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_containerd_filter_by_container_name.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
- name: Test test containerd filter by container id
Expand All @@ -343,9 +370,9 @@ jobs:
uname -a
cat /etc/issue
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_containerd_filter_by_container_id.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_containerd_filter_by_container_id.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_containerd_filter_by_container_id.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_containerd_filter_by_container_id.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
- name: Test redis
Expand All @@ -357,9 +384,9 @@ jobs:
uname -a
cat /etc/issue
if [ -f "/var/lib/kyanos/btf/current.btf" ]; then
bash /host/testdata/test_redis.sh '/host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
bash /host/testdata/test_redis.sh 'sudo /host/kyanos/kyanos $kyanos_log_option --btf /var/lib/kyanos/btf/current.btf'
else
bash /host/testdata/test_redis.sh '/host/kyanos/kyanos $kyanos_log_option'
bash /host/testdata/test_redis.sh 'sudo /host/kyanos/kyanos $kyanos_log_option'
fi
- name: Test k8s
Expand Down
7 changes: 5 additions & 2 deletions agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ func SetupAgent(options ac.AgentOptions) {
return
}

if os.Geteuid() != 0 {
common.AgentLog.Error("Kyanos requires root privileges to run. Please run kyanos with sudo.")
if ok, err := ac.HasPermission(); err != nil {
common.AgentLog.Error("check capabilities failed: ", err)
return
} else if !ok {
common.AgentLog.Error("Kyanos requires CAP_BPF to run. Please run kyanos with sudo or run container in privilege mode.")
return
}

Expand Down
24 changes: 24 additions & 0 deletions agent/common/permission.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package common

import (
"golang.org/x/sys/unix"
)

const (
// capBpf 0000 0000 0000 0000 0000 0000 1000 0000
capBpf = 1 << (unix.CAP_BPF - 32)
// capSysAdmin 0000 0000 0010 0000 0000 0000 0000 0000
capSysAdmin = 1 << unix.CAP_SYS_ADMIN
)

// HasPermission reference: https://man7.org/linux/man-pages/man2/capset.2.html
func HasPermission() (bool, error) {
hdr := unix.CapUserHeader{Version: unix.LINUX_CAPABILITY_VERSION_3}
var data [2]unix.CapUserData
if err := unix.Capget(&hdr, &data[0]); err != nil {
return false, err
}
// Note that the CAP_* values are bit indexes and need to be bit-shifted before ORing into the bit fields.
// Note that 64-bit capabilities use datap[0] and datap[1], whereas 32-bit capabilities use only datap[0].
return data[1].Permitted&capBpf != 0 || data[0].Permitted&capSysAdmin != 0, nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ require (
k8s.io/cri-api v0.31.0
k8s.io/klog/v2 v2.130.1
k8s.io/kubernetes v1.24.17
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
)

require (
Expand Down Expand Up @@ -138,7 +139,6 @@ require (
k8s.io/apimachinery v0.31.1 // indirect
k8s.io/apiserver v0.31.1 // indirect
k8s.io/component-base v0.31.1 // indirect
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
rsc.io/binaryregexp v0.2.0 // indirect
)

Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
github.com/charmbracelet/bubbletea v1.2.2 h1:EMz//Ky/aFS2uLcKqpCst5UOE6z5CFDGRsUpyXz0chs=
github.com/charmbracelet/bubbletea v1.2.2/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM=
github.com/charmbracelet/bubbletea v1.2.4 h1:KN8aCViA0eps9SCOThb2/XPIlea3ANJLUkv3KnQRNCE=
github.com/charmbracelet/bubbletea v1.2.4/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM=
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
Expand Down
28 changes: 28 additions & 0 deletions testdata/run_cap_bpf_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -ex

DOCKER_REGISTRY="$1"
if [ -n "$DOCKER_REGISTRY" ]; then
# 检查是否以 / 结尾
if [[ "$DOCKER_REGISTRY" != */ ]]; then
DOCKER_REGISTRY="${DOCKER_REGISTRY}/"
fi
else
echo "DOCKER_REGISTRY is missing."
fi

# CAP_SYS_RESOURCE reference: https://docs.ebpf.io/linux/concepts/resource-limit/
sudo docker run -d --ulimit memlock=100000000000:100000000000 --cap-add=CAP_SYS_RESOURCE --name alpine $DOCKER_REGISTRY'alpine' sh -c 'sleep 120' || true
sudo docker cp /host/kyanos/kyanos alpine:/
sudo docker cp ./testdata/test_not_add_cap_bpf.sh alpine:/
sudo docker cp /var/lib/kyanos/btf/current.btf alpine:/
sudo docker exec alpine sh -c 'sh /test_not_add_cap_bpf.sh "/kyanos --btf /current.btf"'
sudo docker stop alpine && sudo docker rm alpine

# mount sys reference: https://stackoverflow.com/questions/75808955/error-mounting-sys-kernel-debug-tracing-to-rootfs
sudo docker run -d -v /sys/:/sys/ --privileged --name alpine $DOCKER_REGISTRY'alpine' sh -c 'sleep 120' || true
sudo docker cp /host/kyanos/kyanos alpine:/
sudo docker cp ./testdata/test_add_cap_bpf.sh alpine:/
sudo docker cp /var/lib/kyanos/btf/current.btf alpine:/
sudo docker exec alpine sh -c 'sh /test_add_cap_bpf.sh "/kyanos --btf /current.btf"'
sudo docker stop alpine && sudo docker rm alpine
12 changes: 12 additions & 0 deletions testdata/test_add_cap_bpf.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env sh
set -x

CMD="$1"
FILE_PREFIX="/tmp/kyanos"
LNAME="${FILE_PREFIX}_test_add_cap_bpf_before.log"

timeout 30 ${CMD} watch http --debug-output 2>&1 | tee "${LNAME}" &
wait

cat "${LNAME}"
cat "${LNAME}" | grep -v "requires CAP_BPF"
12 changes: 12 additions & 0 deletions testdata/test_not_add_cap_bpf.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env sh
set -x

CMD="$1"
FILE_PREFIX="/tmp/kyanos"
LNAME="${FILE_PREFIX}_test_not_add_cap_bpf_before.log"

timeout 30 ${CMD} watch http --debug-output 2>&1 | tee "${LNAME}" &
wait

cat "${LNAME}"
cat "${LNAME}" | grep "requires CAP_BPF"

0 comments on commit 6d0b142

Please sign in to comment.