Compare commits

...

2 Commits

Author SHA1 Message Date
Iacopo Rozzo e47c594645
Merge b799abca59 into 0394af7612 2025-07-11 19:44:07 +02:00
Iacopo Rozzo b799abca59 fix(libscap): cgroup v2 path discovery fails with empty cgroup2 mountpoint
Fix the cgroup v2 path discovery mechanism in the presence of cgroup2
mount point with no controllers. The issue has been detected in a RKE
node, where the following empty mountpoint is breaking the detection
logic.

```
none on /host/var/run/calico/cgroup type cgroup2 (rw,relatime,nsdelegate,memory_recursiveprot)
```

The fix consists in stopping the iteration as soon as a mountpoint that
has available controllers listed in the `cgroup.controllers` is
detected.

Signed-off-by: Iacopo Rozzo <iacopo@sysdig.com>
2025-05-16 14:56:54 +02:00
4 changed files with 46 additions and 10 deletions

View File

@ -20,6 +20,7 @@ limitations under the License.
#include <libscap/scap_log.h> #include <libscap/scap_log.h>
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#define scap_log(HANDLE, sev, ...) scap_log_impl(HANDLE->m_log_fn, sev, __VA_ARGS__) #define scap_log(HANDLE, sev, ...) scap_log_impl(HANDLE->m_log_fn, sev, __VA_ARGS__)

View File

@ -22,6 +22,7 @@ limitations under the License.
#include <libscap/scap_const.h> #include <libscap/scap_const.h>
#include <libscap/strerror.h> #include <libscap/strerror.h>
#include <libscap/uthash_ext.h> #include <libscap/uthash_ext.h>
#include <libscap/debug_log_helpers.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
@ -459,13 +460,10 @@ static int32_t get_cgroup_subsystems_v2(struct scap_cgroup_interface* cgi,
char line[SCAP_MAX_PATH_SIZE]; char line[SCAP_MAX_PATH_SIZE];
snprintf(line, sizeof(line), "%s/cgroup.controllers", cgroup_mount); snprintf(line, sizeof(line), "%s/cgroup.controllers", cgroup_mount);
if(access(line, F_OK) == -1) {
// If the file does not exist, return success. Skip
return SCAP_SUCCESS;
}
FILE* cgroup_controllers = fopen(line, "r"); FILE* cgroup_controllers = fopen(line, "r");
if(!cgroup_controllers) { if(!cgroup_controllers) {
scap_debug_log(cgi, "failed to open %s: %s", line, strerror(errno));
return SCAP_FAILURE; return SCAP_FAILURE;
} }
@ -520,8 +518,16 @@ static int32_t get_cgroup_subsystems_v2(struct scap_cgroup_interface* cgi,
// Since there is just one, we don't need to do anything fancy here, just glue the pieces together // Since there is just one, we don't need to do anything fancy here, just glue the pieces together
static int32_t scap_get_cgroup_mount_v2(struct mntent* de, static int32_t scap_get_cgroup_mount_v2(struct mntent* de,
char* mountpoint, char* mountpoint,
const char* host_root) { const char* host_root,
snprintf(mountpoint, SCAP_MAX_PATH_SIZE, "%s/proc/1/root%s", host_root, de->mnt_dir); char* error) {
int len_needed =
snprintf(mountpoint, SCAP_MAX_PATH_SIZE, "%s/proc/1/root%s", host_root, de->mnt_dir);
if(len_needed < 0) {
return scap_errprintf(error, errno, "cgroup mount path encoding error");
}
if(len_needed >= SCAP_MAX_PATH_SIZE) {
return scap_errprintf(error, 0, "cgroup mount path too long");
}
return SCAP_SUCCESS; return SCAP_SUCCESS;
} }
@ -641,10 +647,35 @@ int32_t scap_cgroup_interface_init(struct scap_cgroup_interface* cgi,
error); error);
} }
} else if(strcmp(de->mnt_type, "cgroup2") == 0) { } else if(strcmp(de->mnt_type, "cgroup2") == 0) {
scap_get_cgroup_mount_v2(de, cgi->m_mount_v2, host_root); scap_debug_log(cgi, "found cgroup v2 mountpoint %s", de->mnt_dir);
get_cgroup_subsystems_v2(cgi, &cgi->m_subsystems_v2, cgi->m_mount_v2); if(scap_get_cgroup_mount_v2(de, cgi->m_mount_v2, host_root, error) == SCAP_SUCCESS) {
if(cgi->m_in_cgroupns) { if(get_cgroup_subsystems_v2(cgi, &cgi->m_subsystems_v2, cgi->m_mount_v2) ==
scap_get_cgroup_self_v2_cgroupns(de, cgi->m_self_v2, host_root, pid_str); SCAP_FAILURE) {
scap_errprintf(error,
0,
"failed to parse %s/cgroup.controllers",
cgi->m_mount_v2);
// Reset the mountpoint as we failed to read the
// controllers
de->mnt_dir[0] = '\0';
continue;
}
if(cgi->m_in_cgroupns) {
scap_get_cgroup_self_v2_cgroupns(de, cgi->m_self_v2, host_root, pid_str);
}
// If we found a cgroup v2 mountpoint with controllers, we can
// stop searching
if(cgi->m_subsystems_v2.len > 0) {
scap_debug_log(cgi,
"found cgroup v2 mountpoint with controllers: %s",
cgi->m_mount_v2);
break;
}
} else {
scap_debug_log(cgi,
"failed to get cgroup mount v2 path for mountpoint %s: %s",
de->mnt_dir,
error);
} }
} }
} }

View File

@ -22,6 +22,7 @@ limitations under the License.
#include <stdint.h> #include <stdint.h>
#include <libscap/scap_cgroup_set.h> #include <libscap/scap_cgroup_set.h>
#include <libscap/scap_log.h>
#define FOR_EACH_SUBSYS(cgset, subsys) \ #define FOR_EACH_SUBSYS(cgset, subsys) \
for(const char *subsys = (cgset)->path, *_end = (cgset)->path + (cgset)->len; subsys < _end; \ for(const char *subsys = (cgset)->path, *_end = (cgset)->path + (cgset)->len; subsys < _end; \
@ -54,6 +55,8 @@ struct scap_cgroup_interface {
char m_self_v2[SCAP_MAX_PATH_SIZE]; char m_self_v2[SCAP_MAX_PATH_SIZE];
bool m_in_cgroupns; bool m_in_cgroupns;
falcosecurity_log_fn m_log_fn;
}; };
int32_t scap_cgroup_interface_init(struct scap_cgroup_interface* cgi, int32_t scap_cgroup_interface_init(struct scap_cgroup_interface* cgi,

View File

@ -62,6 +62,7 @@ int32_t scap_linux_init_platform(struct scap_platform* platform,
linux_platform->m_proc_scan_timeout_ms = oargs->proc_scan_timeout_ms; linux_platform->m_proc_scan_timeout_ms = oargs->proc_scan_timeout_ms;
linux_platform->m_proc_scan_log_interval_ms = oargs->proc_scan_log_interval_ms; linux_platform->m_proc_scan_log_interval_ms = oargs->proc_scan_log_interval_ms;
linux_platform->m_log_fn = oargs->log_fn; linux_platform->m_log_fn = oargs->log_fn;
linux_platform->m_cgroups.m_log_fn = oargs->log_fn;
if(scap_os_get_machine_info(&platform->m_machine_info, lasterr) != SCAP_SUCCESS) { if(scap_os_get_machine_info(&platform->m_machine_info, lasterr) != SCAP_SUCCESS) {
return SCAP_FAILURE; return SCAP_FAILURE;