bpf: put canonicalized section name in bpf_prog_def

Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I8bc5c888f982dc872ac68840ae6c136a798384d9
This commit is contained in:
Maciej Żenczykowski 2025-08-04 18:19:33 -07:00
commit adb0f9e2a4
3 changed files with 25 additions and 26 deletions

View file

@ -110,7 +110,6 @@ inline bool isUserdebug() {
static unsigned int page_size = static_cast<unsigned int>(getpagesize());
typedef struct {
string name; // The canonicalized section name.
string program_name;
vector<char> data;
vector<char> rel_data;
@ -383,8 +382,6 @@ int readCodeSections(ElfObject& elfObj, vector<codeSection>& cs) {
if (name.find('/') != std::string::npos) abort(); // There should only be one!
cs_temp.name = name;
ret = elfObj.readSectionByIdx(i, cs_temp.data);
if (ret) return ret;
ALOGV("Loaded code section %d (%s)", i, name.c_str());
@ -1050,33 +1047,27 @@ static int loadCodeSections(ElfObject& elfObj, vector<codeSection>& cs, const st
for (int i = 0; i < (int)cs.size(); i++) {
unique_fd& fd = cs[i].prog_fd;
int ret;
string name = cs[i].name;
if (!cs[i].prog_def.has_value()) {
ALOGE("[%d] '%s' missing program definition! bad bpf.o build?", i, name.c_str());
ALOGE("[%d] missing program definition! bad bpf.o build?", i);
return -EINVAL;
}
unsigned min_kver = cs[i].prog_def->min_kver;
unsigned max_kver = cs[i].prog_def->max_kver;
ALOGD("cs[%d].name:%s min_kver:%x .max_kver:%x (kvers:%x)", i, name.c_str(), min_kver,
max_kver, kvers);
ALOGD("cs[%d].name:%s min_kver:%x .max_kver:%x (kvers:%x)",
i, cs[i].prog_def->name(), min_kver, max_kver, kvers);
if (kvers < min_kver) continue;
if (kvers >= max_kver) continue;
unsigned bpfMinVer = cs[i].prog_def->bpfloader_min_ver;
unsigned bpfMaxVer = cs[i].prog_def->bpfloader_max_ver;
ALOGD("cs[%d].name:%s requires bpfloader version [0x%05x,0x%05x)", i, name.c_str(),
bpfMinVer, bpfMaxVer);
ALOGD("cs[%d].name:%s requires bpfloader version [0x%05x,0x%05x)",
i, cs[i].prog_def->name(), bpfMinVer, bpfMaxVer);
if (bpfloader_ver < bpfMinVer) continue;
if (bpfloader_ver >= bpfMaxVer) continue;
// strip any potential $foo suffix
// this can be used to provide duplicate programs
// conditionally loaded based on running kernel version
name = name.substr(0, name.find_last_of('$'));
bool reuse = false;
if (access(cs[i].prog_def->pin_location, F_OK) == 0) {
fd.reset(retrieveProgram(cs[i].prog_def->pin_location));
@ -1097,7 +1088,7 @@ static int loadCodeSections(ElfObject& elfObj, vector<codeSection>& cs, const st
.expected_attach_type = cs[i].prog_def->attach_type,
};
if (isAtLeastKernelVersion(4, 15, 0))
strlcpy(req.prog_name, cs[i].name.c_str(), sizeof(req.prog_name));
strlcpy(req.prog_name, cs[i].prog_def->name(), sizeof(req.prog_name));
fd.reset(bpf(BPF_PROG_LOAD, req));
// Kernel should have NULL terminated the log buffer, but force it anyway for safety
@ -1110,7 +1101,7 @@ static int loadCodeSections(ElfObject& elfObj, vector<codeSection>& cs, const st
bool log_oneline = !strchr(log_buf, '\n');
ALOGD("BPF_PROG_LOAD call for %s (%s) returned '%s' fd: %d (%s)", elfObj.path,
cs[i].name.c_str(), log_oneline ? log_buf : "{multiline}",
cs[i].prog_def->name(), log_oneline ? log_buf : "{multiline}",
fd.get(), !fd.ok() ? std::strerror(errno) : "ok");
if (!fd.ok()) {
@ -1125,10 +1116,10 @@ static int loadCodeSections(ElfObject& elfObj, vector<codeSection>& cs, const st
if (cs[i].prog_def->optional) {
ALOGW("failed program %s is marked optional - continuing...",
cs[i].name.c_str());
cs[i].prog_def->name());
continue;
}
ALOGE("non-optional program %s failed to load.", cs[i].name.c_str());
ALOGE("non-optional program %s failed to load.", cs[i].prog_def->name());
}
}
@ -1188,9 +1179,8 @@ static int prepareLoadProgs(const struct bpf_object* obj, const vector<codeSecti
unsigned kvers = kernelVersion();
for (int i = 0; i < (int)cs.size(); i++) {
string name = cs[i].name;
if (!cs[i].prog_def.has_value()) {
ALOGE("[%d] '%s' missing program definition! bad bpf.o build?", i, name.c_str());
ALOGE("[%d] missing program definition! bad bpf.o build?", i);
return -EINVAL;
}
string program_name = cs[i].program_name;
@ -1204,7 +1194,7 @@ static int prepareLoadProgs(const struct bpf_object* obj, const vector<codeSecti
unsigned max_kver = cs[i].prog_def->max_kver;
if (kvers < min_kver || kvers >= max_kver) {
ALOGD("skipping prog %s: kernel version 0x%x is outside required range [0x%x, 0x%x)",
name.c_str(), kvers, min_kver, max_kver);
cs[i].prog_def->name(), kvers, min_kver, max_kver);
bpf_program__set_autoload(prog, false);
continue;
}
@ -1213,7 +1203,7 @@ static int prepareLoadProgs(const struct bpf_object* obj, const vector<codeSecti
unsigned bpfMaxVer = cs[i].prog_def->bpfloader_max_ver;
if (bpfloader_ver < bpfMinVer || bpfloader_ver >= bpfMaxVer) {
ALOGD("skipping prog %s: bpfloader 0x%05x is outside required range [0x%05x, 0x%05x)",
name.c_str(), bpfloader_ver, bpfMinVer, bpfMaxVer);
cs[i].prog_def->name(), bpfloader_ver, bpfMinVer, bpfMaxVer);
bpf_program__set_autoload(prog, false);
continue;
}
@ -1265,11 +1255,9 @@ static int pinProgs(const struct bpf_object * obj,
// This program was skipped
if (!bpf_program__autoload(prog)) continue;
string name = cs[i].name;
name = name.substr(0, name.find_last_of('$'));
if (access(cs[i].prog_def->pin_location, F_OK) == 0) {
// TODO: Skip loading lower priority program
ALOGI("Higher priority program is already pinned, skip pinning %s", cs[i].name.c_str());
ALOGI("Higher priority program is already pinned, skip pinning %s", cs[i].prog_def->name());
continue;
}

View file

@ -547,6 +547,7 @@ static long (*bpf_trace_printk)(const char* fmt, int fmt_size, ...) = (void*) BP
.bpfloader_max_ver = (max_loader), \
.create_location = CREATE_LOCATION(selinux), \
.pin_location = "/sys/fs/bpf/" pindir "/prog_" BPF_OBJ_NAME "_" #TYPE "_" #NAME "\0", \
.name_idx = __builtin_strlen("/sys/fs/bpf/" pindir "/prog_" BPF_OBJ_NAME "_"), \
}; \
SECTION(#TYPE "/" #NAME "$" #VER) \
long TYPE##_##NAME##_##VER

View file

@ -186,10 +186,20 @@ struct bpf_prog_def {
char create_location[BPF_DEF_CHAR_ARRAY_SIZE];
char pin_location[BPF_DEF_CHAR_ARRAY_SIZE];
unsigned int name_idx;
#ifdef __cplusplus
const char * name() const { return this->pin_location + this->name_idx; }
#endif
};
#ifdef __cplusplus
static_assert(std::is_pod_v<struct bpf_prog_def>);
static_assert(std::is_standard_layout_v<struct bpf_prog_def>);
#endif
// This needs to be updated whenever the above structure definition is expanded.
// These asserts are here to make sure we have cross-6-arch consistency.
_Static_assert(sizeof(struct bpf_prog_def) == 36 + 2 * BPF_DEF_CHAR_ARRAY_SIZE, "wrong sizeof struct bpf_prog_def");
_Static_assert(sizeof(struct bpf_prog_def) == 40 + 2 * BPF_DEF_CHAR_ARRAY_SIZE, "wrong sizeof struct bpf_prog_def");
_Static_assert(__alignof__(struct bpf_prog_def) == 4, "__alignof__ struct bpf_prog_def != 4");
_Static_assert(_Alignof(struct bpf_prog_def) == 4, "_Alignof struct bpf_prog_def != 4");