Skip to content

Commit

Permalink
Merge pull request #1550 from criblio/feat/1523-filter-existing-conta…
Browse files Browse the repository at this point in the history
…iners

Apply rules to existing containers (#1523)
  • Loading branch information
seanvaleo authored Jul 14, 2023
2 parents 677684c + 00cd78c commit e44c367
Show file tree
Hide file tree
Showing 13 changed files with 380 additions and 32 deletions.
10 changes: 10 additions & 0 deletions cleanup_after_start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
#

PRELOAD_PATH="/etc/ld.so.preload"
LIBSCOPE_PATH="/usr/lib/libscope.so"
PROFILE_SCOPE_SCRIPT="/etc/profile.d/scope.sh"
USR_APPSCOPE_DIR="/usr/lib/appscope/"
TMP_APPSCOPE_DIR="/tmp/appscope/"
CRIBL_APPSCOPE_DIR="$CRIBL_HOME/appscope/"

echo "Following script will try to remove following files:"
echo "- $PRELOAD_PATH"
echo "- $LIBSCOPE_PATH"
echo "- $PROFILE_SCOPE_SCRIPT"
echo "- $USR_APPSCOPE_DIR"
echo "- $TMP_APPSCOPE_DIR"
Expand All @@ -35,6 +37,14 @@ else
echo "$PRELOAD_PATH file was missing. Continue..."
fi

# This one is a symbolic link
if [ -L $LIBSCOPE_PATH ] ; then
rm $LIBSCOPE_PATH
echo "$LIBSCOPE_PATH file was removed"
else
echo "$LIBSCOPE_PATH file was missing. Continue..."
fi

if [ -f $PROFILE_SCOPE_SCRIPT ] ; then
rm $PROFILE_SCOPE_SCRIPT
echo "$PROFILE_SCOPE_SCRIPT file was removed"
Expand Down
7 changes: 5 additions & 2 deletions cli/loader/loader.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package loader

import (
"fmt"
"os"
"os/exec"
"strconv"
Expand Down Expand Up @@ -52,10 +53,12 @@ func (sL *ScopeLoader) Preload(path, rootdir string) (string, error) {
}

// Mount Command
func (sL *ScopeLoader) Mount(source, dest, rootdir string) (string, error) {
func (sL *ScopeLoader) Mount(path string, cPid int, rootdir string) (string, error) {
args := make([]string, 0)
args = append(args, "--mount")
args = append(args, source+","+dest)
args = append(args, path)
args = append(args, "--namespace")
args = append(args, fmt.Sprint(cPid))
if rootdir != "" {
args = append(args, "--rootdir")
args = append(args, rootdir)
Expand Down
6 changes: 3 additions & 3 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ __attribute__((constructor)) void cli_constructor() {
fprintf(stderr, "error: --rules and --service/--unservice cannot be used together\n");
exit(EXIT_FAILURE);
}
if (opt_namespace && (!opt_service && !opt_unservice)) {
fprintf(stderr, "error: --namespace option requires --service/--unservice option\n");
if (opt_namespace && (!opt_service && !opt_unservice && !opt_mount)) {
fprintf(stderr, "error: --namespace option requires --service/--unservice or --mount option\n");
exit(EXIT_FAILURE);
}
if (opt_passthrough && (opt_ldattach || opt_lddetach || opt_namespace ||
Expand Down Expand Up @@ -292,7 +292,7 @@ __attribute__((constructor)) void cli_constructor() {
if (opt_install) exit(cmdInstall(arg_rootdir));
if (opt_rules) exit(cmdRules(arg_rules, arg_rootdir));
if (opt_preload) exit(cmdPreload(arg_preload, arg_rootdir));
if (opt_mount) exit(cmdMount(arg_mount, arg_rootdir));
if (opt_mount) exit(cmdMount(nspid, arg_mount, arg_rootdir));
if (opt_service) exit(cmdService(arg_service, nspid));
if (opt_unservice) exit(cmdUnservice(nspid));
if (opt_patch) exit(patchLibrary(arg_patch, FALSE) == PATCH_FAILED);
Expand Down
104 changes: 104 additions & 0 deletions cli/rules/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package rules

import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"

"github.com/criblio/scope/libscope"
"github.com/criblio/scope/loader"
Expand Down Expand Up @@ -184,6 +186,78 @@ func Add(rulesFile libscope.Rules, addProc, procArg, sourceid, rootdir string, r

// TBC ? perform a scope detach to all processes that do not match anything in the rules file

////////////////////////////////////////////
// Apply rules to existing containers
////////////////////////////////////////////

// Don't do the below if (not on host AND no rootdir provided)
if util.InContainer() && rootdir == "" {
return nil
}

// Only if this is the first entry in the file
// Rules will be applied in future containers by another mechanism (runc interposition)
if len(rulesFile.Allow) == 1 {

// For each existing container
cPids := util.GetContainersPids(rootdir)
for _, cPid := range cPids {
containerRootdir := fmt.Sprintf("%s/proc/%d/root", rootdir, cPid)

// Note: Install must be first so we don't trample on the host's files
// The install is required even though we are mounting /usr/lib/appscope
// because we need the /usr/lib/libscope.so link to be created AND we need
// it to point to the correct version (glibc/musl)

// Install the library
stdoutStderr, err = ld.Install(containerRootdir)
if err != nil {
log.Warn().
Err(err).
Str("loaderDetails", stdoutStderr).
Msgf("Install library in %s namespace failed.", containerRootdir)
return err
}

// Set ld.preload.so to point to the library
if stdoutStderr, err := ld.Preload("auto", containerRootdir); err != nil {
log.Warn().
Err(err).
Str("loaderDetails", stdoutStderr).
Msgf("Set /etc/ld.so.preload in %s namespace failed.", containerRootdir)
return err
}

// Mount `scope_rules` from the host into the container
// ? support CRIBL_HOME
stdoutStderr, err := ld.Mount("/usr/lib/appscope", cPid, rootdir)
if err != nil {
log.Warn().
Err(err).
Str("loaderDetails", stdoutStderr).
Msgf("Mount /usr/lib/appscope in %d namespace failed.", cPid)
return err
}

// Mount unix socket from the host into the container
unixPath = filepath.Dir(unixPath) // Strip the filename. We need to mount the dir
// Hack for now, don't mount /var/run/... - it won't work. Just mount /run/...
unixPath = strings.TrimPrefix(unixPath, "/var")
if unixPath != "" {
stdoutStderr, err = ld.Mount(unixPath, cPid, rootdir)
if err != nil {
log.Warn().
Err(err).
Str("loaderDetails", stdoutStderr).
Msgf("Mount /usr/lib/appscope in %d namespace failed.", cPid)
return err
}
}

// Attach is already taken care of, we attached to everything in rootdir and children
}
}

return nil
}

Expand Down Expand Up @@ -285,5 +359,35 @@ func Remove(rulesFile libscope.Rules, remProc, procArg, sourceid, rootdir string
}
}

////////////////////////////////////////////
// Apply rules to existing containers
////////////////////////////////////////////

// Don't do the below if (not on host AND no rootdir provided)
if util.InContainer() && rootdir == "" {
return nil
}

// Only if this is the last entry in the file
if len(rulesFile.Allow) == 0 {

// For each existing container
cPids := util.GetContainersPids(rootdir)
for _, cPid := range cPids {
containerRootdir := fmt.Sprintf("%s/proc/%d/root", rootdir, cPid)

// Unset ld.preload.so
if stdoutStderr, err := ld.Preload("off", containerRootdir); err != nil {
log.Warn().
Err(err).
Str("loaderDetails", stdoutStderr).
Msgf("Unset /etc/ld.so.preload in %s namespace failed.", containerRootdir)
return err
}

// Detach is already taken care of, we detached from everything in rootdir and children
}
}

return nil
}
22 changes: 11 additions & 11 deletions cli/util/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var (
)

// Get the LXD server unix socket
func getLXDServerSocket() string {
func getLXDServerSocket(rootdir string) string {
socketPaths := []string{"/var/lib/lxd/unix.socket", "/var/snap/lxd/common/lxd/unix.socket"}
for _, path := range socketPaths {
if _, err := os.Stat(path); err == nil {
Expand All @@ -23,8 +23,8 @@ func getLXDServerSocket() string {
}

// Get the List of PID(s) related to LXC container
func GetLXCPids() ([]int, error) {
lxdUnixPath := getLXDServerSocket()
func GetLXCPids(rootdir string) ([]int, error) {
lxdUnixPath := getLXDServerSocket(rootdir)
if lxdUnixPath == "" {
return nil, ErrLXDSocketNotAvailable
}
Expand All @@ -50,32 +50,32 @@ func GetLXCPids() ([]int, error) {
}

// Get the List of PID(s) related to containerd container
func GetContainerDPids() ([]int, error) {
return getContainerRuntimePids("containerd-shim")
func GetContainerDPids(rootdir string) ([]int, error) {
return getContainerRuntimePids(rootdir, "containerd-shim")
}

// Get the List of PID(s) related to Podman container
func GetPodmanPids() ([]int, error) {
return getContainerRuntimePids("conmon")
func GetPodmanPids(rootdir string) ([]int, error) {
return getContainerRuntimePids(rootdir, "conmon")
}

// Get the List of PID(s) related to specific container runtime
func getContainerRuntimePids(runtimeProc string) ([]int, error) {
runtimeContPids, err := PidScopeMapByProcessName("", runtimeProc)
func getContainerRuntimePids(rootdir, runtimeProc string) ([]int, error) {
runtimeContPids, err := PidScopeMapByProcessName(rootdir, runtimeProc)
if err != nil {
return nil, err
}
pids := make([]int, 0, len(runtimeContPids))

for runtimeContPid := range runtimeContPids {
childrenPids, err := PidChildren("", runtimeContPid)
childrenPids, err := PidChildren(rootdir, runtimeContPid)
if err != nil {
return nil, err
}

// Iterate over all the children to found container init process
for _, childPid := range childrenPids {
status, _ := PidInitContainer("", childPid)
status, _ := PidInitContainer(rootdir, childPid)
if status {
pids = append(pids, childPid)
}
Expand Down
10 changes: 5 additions & 5 deletions cli/util/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,12 +475,12 @@ func PidExists(rootdir string, pid int) bool {
}

// containerPids returns list of PID's of currently running containers
func containerPids() []int {
func containerPids(rootdir string) []int {
cPids := []int{}
ctrFuncs := []func() ([]int, error){GetContainerDPids, GetPodmanPids, GetLXCPids}
ctrFuncs := []func(string) ([]int, error){GetContainerDPids, GetPodmanPids, GetLXCPids}

for _, ctrFunc := range ctrFuncs {
ctrPids, err := ctrFunc()
ctrPids, err := ctrFunc(rootdir)
if err != nil {
continue
}
Expand All @@ -499,7 +499,7 @@ func PidGetRefPidForMntNamespace(rootdir string, targetPid int) int {
}

// First check if the namespace used by process is the same namespace as CLI
nsInfo, err := os.Readlink(fmt.Sprintf("%s/proc/self/ns/mnt", rootdir))
nsInfo, err := os.Readlink(fmt.Sprintf("/proc/self/ns/mnt"))
if err != nil {
return -1
}
Expand All @@ -509,7 +509,7 @@ func PidGetRefPidForMntNamespace(rootdir string, targetPid int) int {
}

// Check if the namespace used by process belongs to one of the detected containers
ctrPids := containerPids()
ctrPids := containerPids(rootdir)
for _, nsPid := range ctrPids {
nsInfo, err := os.Readlink(fmt.Sprintf("%s/proc/%d/ns/mnt", rootdir, nsPid))
if err != nil {
Expand Down
9 changes: 5 additions & 4 deletions cli/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,11 @@ func RemoveEmptyStrings(s []string) []string {
}

// GetContainersPids gets the list of PID(s) related to containers
func GetContainersPids() []int {
// Only works from a container for detecting non-LXC containers
func GetContainersPids(rootdir string) []int {
cPids := []int{}

ctrDPids, err := GetContainerDPids()
ctrDPids, err := GetContainerDPids(rootdir)
if err != nil {
log.Error().
Err(err).
Expand All @@ -434,7 +435,7 @@ func GetContainersPids() []int {
cPids = append(cPids, ctrDPids...)
}

podmanPids, err := GetPodmanPids()
podmanPids, err := GetPodmanPids(rootdir)
if err != nil {
log.Error().
Err(err).
Expand All @@ -444,7 +445,7 @@ func GetContainersPids() []int {
cPids = append(cPids, podmanPids...)
}

lxcPids, err := GetLXCPids()
lxcPids, err := GetLXCPids(rootdir)
if err != nil {
switch {
case errors.Is(err, ErrLXDSocketNotAvailable):
Expand Down
Loading

0 comments on commit e44c367

Please sign in to comment.