// Path
const char* path;
+
+ // ELF
+ Elf* elf;
};
#define pakfire_linter_file_info(lfile, format, ...) \
#define pakfire_linter_file_error(lfile, format, ...) \
pakfire_linter_result(lfile->linter, lfile->file, PAKFIRE_LINTER_ERROR, format, ## __VA_ARGS__)
+static int pakfire_linter_file_init_libelf(struct pakfire_linter_file* lfile) {
+ // Initialize libelf
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ ERROR(lfile->ctx, "Could not initialize libelf: %s\n", elf_errmsg(-1));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pakfire_linter_file_open_elf(struct pakfire_linter_file* lfile) {
+ int r;
+
+ // Initialize libelf
+ r = pakfire_linter_file_init_libelf(lfile);
+ if (r < 0)
+ return r;
+
+ // Parse the ELF header
+ lfile->elf = elf_memory(lfile->data, lfile->length);
+ if (!lfile->elf)
+ return -errno;
+
+ return 0;
+}
+
/*
Maps the file into memory
*/
goto ERROR;
}
+ // Initialize libelf
+ r = pakfire_linter_file_open_elf(l);
+ if (r < 0) {
+ ERROR(l->ctx, "Could not initialize libelf: %s\n", strerror(-r));
+ goto ERROR;
+ }
+
// Return the pointer
*lfile = pakfire_linter_file_ref(l);
static void pakfire_linter_file_free(struct pakfire_linter_file* lfile) {
int r;
+ if (lfile->elf)
+ elf_end(lfile->elf);
+
if (lfile->data) {
r = munmap(lfile->data, lfile->length);
if (r < 0)
ERROR(lfile->ctx, "Could not unmmap %s: %m\n", lfile->path);
}
+ if (lfile->fd >= 0)
+ close(lfile->fd);
+
if (lfile->linter)
pakfire_linter_unref(lfile->linter);
if (lfile->file)
pakfire_file_unref(lfile->file);
if (lfile->ctx)
pakfire_ctx_unref(lfile->ctx);
- if (lfile->fd >= 0)
- close(lfile->fd);
+ free(lfile);
}
struct pakfire_linter_file* pakfire_linter_file_ref(struct pakfire_linter_file* lfile) {
return 0;
}
-static int pakfire_linter_file_init_libelf(struct pakfire_linter_file* lfile) {
- // Initialize libelf
- if (elf_version(EV_CURRENT) == EV_NONE) {
- ERROR(lfile->ctx, "Could not initialize libelf: %s\n", elf_errmsg(-1));
- return -EINVAL;
- }
-
- return 0;
-}
static int pakfire_linter_file_is_elf(struct pakfire_linter_file* lfile) {
- Elf* elf = NULL;
- int r;
-
- // Initialize libelf
- r = pakfire_linter_file_init_libelf(lfile);
- if (r < 0)
- return r;
-
- // Parse the ELF header
- elf = elf_begin(lfile->fd, ELF_C_READ, NULL);
- if (!elf) {
- ERROR(lfile->ctx, "Could not open ELF file: %s\n", elf_errmsg(-1));
- r = -EINVAL;
- goto ERROR;
- }
+ // Don't know if we don't have an ELF object
+ if (!lfile->elf)
+ return -EINVAL;
- switch (elf_kind(elf)) {
+ switch (elf_kind(lfile->elf)) {
case ELF_K_ELF:
- r = 1;
- break;
+ return 1;
// Ignore everything else
default:
- r = 0;
break;
}
-ERROR:
- if (elf)
- elf_end(elf);
-
- return r;
-}
-
-/*
- A helper function that opens an ELF file and calls a callback.
-*/
-static int pakfire_linter_file_elf(struct pakfire_linter_file* lfile,
- int (*callback)(struct pakfire_linter_file* lfile, Elf* elf, void* data), void* data) {
- Elf* elf = NULL;
- int r;
-
- // Initialize libelf
- r = pakfire_linter_file_init_libelf(lfile);
- if (r < 0)
- return r;
-
- // Parse the ELF header
- elf = elf_begin(lfile->fd, ELF_C_READ, NULL);
- if (!elf) {
- ERROR(lfile->ctx, "Could not open ELF file: %s\n", elf_errmsg(-1));
- r = -EINVAL;
- goto ERROR;
- }
-
- // Check if this is an ELF file
- switch (elf_kind(elf)) {
- case ELF_K_ELF:
- break;
-
- default:
- ERROR(lfile->ctx, "%s is not an ELF object\n", lfile->path);
- r = -EINVAL;
- goto ERROR;
- }
-
- // Call the callback
- r = callback(lfile, elf, data);
-
-ERROR:
- if (elf)
- elf_end(elf);
-
- return r;
+ return 0;
}
-static int __pakfire_linter_file_get_elf_type(
- struct pakfire_linter_file* lfile, Elf* elf, void* data) {
+static int pakfire_linter_file_get_elf_type(struct pakfire_linter_file* lfile) {
GElf_Ehdr ehdr = {};
- int* type = data;
+ // Check if have an ELF object
+ if (lfile->elf)
+ return -EINVAL;
// Fetch the ELF header
- if (!gelf_getehdr(elf, &ehdr)) {
+ if (!gelf_getehdr(lfile->elf, &ehdr)) {
ERROR(lfile->ctx, "Could not parse ELF header: %s\n", elf_errmsg(-1));
return -EINVAL;
}
- // Store the type
- *type = ehdr.e_type;
-
- return 0;
-}
-
-static int pakfire_linter_file_get_elf_type(struct pakfire_linter_file* lfile) {
- int type = ET_NONE;
- int r;
-
- // Fetch the type
- r = pakfire_linter_file_elf(lfile, __pakfire_linter_file_get_elf_type, &type);
- if (r < 0)
- return r;
-
- return type;
+ return ehdr.e_type;
}
typedef int (*__pakfire_linter_file_for_elf_section_callback)(struct pakfire_linter_file* lfile,
- Elf* elf, const Elf_Scn* section, const GElf_Shdr* shdr, Elf_Data* data);
+ const Elf_Scn* section, const GElf_Shdr* shdr, Elf_Data* data);
static int pakfire_linter_file_for_elf_section(struct pakfire_linter_file* lfile,
- Elf* elf, const Elf64_Word type, __pakfire_linter_file_for_elf_section_callback callback) {
+ const Elf64_Word type, __pakfire_linter_file_for_elf_section_callback callback) {
Elf_Scn* section = NULL;
GElf_Shdr shdr;
Elf_Data* data;
// Walk through all sections
for (;;) {
- section = elf_nextscn(elf, section);
+ section = elf_nextscn(lfile->elf, section);
if (!section)
break;
data = elf_getdata(section, NULL);
// Call the callback
- r = callback(lfile, elf, section, &shdr, data);
+ r = callback(lfile, section, &shdr, data);
if (r)
break;
}
static int pakfire_linter_file_get_elf_section(struct pakfire_linter_file* lfile,
- Elf* elf, const Elf64_Word type, Elf_Scn** section, GElf_Shdr* header, Elf_Data** data) {
+ const Elf64_Word type, Elf_Scn** section, GElf_Shdr* header, Elf_Data** data) {
Elf_Scn* s = NULL;
-
GElf_Shdr shdr;
// Walk through all sections
for (;;) {
- s = elf_nextscn(elf, s);
+ s = elf_nextscn(lfile->elf, s);
if (!s)
break;
return 1;
}
-static int pakfire_linter_file_elf_dyn_walk(struct pakfire_linter_file* lfile, Elf* elf,
- int (*callback)(struct pakfire_linter_file* lfile, Elf* elf,
+static int pakfire_linter_file_elf_dyn_walk(struct pakfire_linter_file* lfile,
+ int (*callback)(struct pakfire_linter_file* lfile,
const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data), void* data) {
Elf_Scn* dynamic = NULL;
GElf_Shdr shdr;
int r;
// Find the dynamic linking information
- r = pakfire_linter_file_get_elf_section(lfile, elf, SHT_DYNAMIC, &dynamic, &shdr, &elf_data);
+ r = pakfire_linter_file_get_elf_section(lfile, SHT_DYNAMIC, &dynamic, &shdr, &elf_data);
if (r) {
DEBUG(lfile->ctx, "%s does not have a dynamic section\n", lfile->path);
return 0;
break;
// Call the callback
- r = callback(lfile, elf, &shdr, &dyn, data);
+ r = callback(lfile, &shdr, &dyn, data);
if (r)
return r;
}
return 0;
}
-
static int pakfire_linter_file_check_pie(struct pakfire_linter_file* lfile) {
switch (pakfire_linter_file_get_elf_type(lfile)) {
// Shared Object files are good
return pakfire_linter_file_error(lfile, "Missing PIE");
}
-static int __pakfire_linter_file_check_ssp(
- struct pakfire_linter_file* lfile, Elf* elf, void* data) {
+static int pakfire_linter_file_check_ssp(struct pakfire_linter_file* lfile) {
Elf_Scn* symtab = NULL;
GElf_Shdr shdr;
Elf_Data* elf_data = NULL;
const char* name = NULL;
int r;
+ // This check will be skipped for these files
+ static const char* whitelist[] = {
+ "/usr/lib64/libgcc_s.so.*",
+ "/usr/lib64/libmvec.so.*",
+ NULL,
+ };
+
+ // Do not perform this check for runtime linkers
+ if (pakfire_file_matches(lfile->file, "/usr/lib*/ld-*.so*"))
+ return 0;
+
+ // Check if this file is whitelisted
+ for (const char** path = whitelist; *path; path++) {
+ if (pakfire_file_matches(lfile->file, *path)) {
+ DEBUG(lfile->ctx, "Skipping SSP check for whitelisted file %s\n", lfile->path);
+ return 0;
+ }
+ }
+
// Fetch the symbol table
- r = pakfire_linter_file_get_elf_section(lfile, elf, SHT_SYMTAB, &symtab, &shdr, &elf_data);
+ r = pakfire_linter_file_get_elf_section(lfile, SHT_SYMTAB, &symtab, &shdr, &elf_data);
if (r) {
ERROR(lfile->ctx, "%s has no symbol table\n", lfile->path);
return 1;
gelf_getsym(elf_data, i, &symbol);
// Fetch the symbol name
- name = elf_strptr(elf, shdr.sh_link, symbol.st_name);
+ name = elf_strptr(lfile->elf, shdr.sh_link, symbol.st_name);
// Skip empty section names
if (!name || !*name)
return pakfire_linter_file_error(lfile, "Missing Stack Smashing Protection");
}
-static int pakfire_linter_file_check_ssp(struct pakfire_linter_file* lfile) {
- // This check will be skipped for these files
- static const char* whitelist[] = {
- "/usr/lib64/libgcc_s.so.*",
- "/usr/lib64/libmvec.so.*",
- NULL,
- };
-
- // Do not perform this check for runtime linkers
- if (pakfire_file_matches(lfile->file, "/usr/lib*/ld-*.so*"))
- return 0;
-
- // Check if this file is whitelisted
- for (const char** path = whitelist; *path; path++) {
- if (pakfire_file_matches(lfile->file, *path)) {
- DEBUG(lfile->ctx, "Skipping SSP check for whitelisted file %s\n", lfile->path);
- return 0;
- }
- }
-
- return pakfire_linter_file_elf(lfile, __pakfire_linter_file_check_ssp, NULL);
-}
-
-static int __pakfire_linter_file_check_execstack(
- struct pakfire_linter_file* lfile, Elf* elf, void* data) {
+static int pakfire_linter_file_check_execstack(struct pakfire_linter_file* lfile) {
GElf_Phdr phdr;
int r;
size_t phnum = 0;
// Fetch the total numbers of program headers
- r = elf_getphdrnum(elf, &phnum);
+ r = elf_getphdrnum(lfile->elf, &phnum);
if (r) {
ERROR(lfile->ctx,
"Could not fetch number of program headers: %s\n", elf_errmsg(-1));
// Walk through all program headers
for (unsigned int i = 0; i < phnum; i++) {
- if (!gelf_getphdr(elf, i, &phdr)) {
+ if (!gelf_getphdr(lfile->elf, i, &phdr)) {
ERROR(lfile->ctx, "Could not parse program header: %s\n", elf_errmsg(-1));
return -ENOTSUP;
}
return 0;
}
-static int pakfire_linter_file_check_execstack(struct pakfire_linter_file* lfile) {
- return pakfire_linter_file_elf(lfile, __pakfire_linter_file_check_execstack, NULL);
-}
-
static int __pakfire_linter_file_has_bind_now(struct pakfire_linter_file* lfile,
- Elf* elf, const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
+ const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
int* has_bind_now = (int*)data;
switch (dyn->d_tag) {
return 0;
}
-static int __pakfire_linter_file_check_relro(
- struct pakfire_linter_file* lfile, Elf* elf, void* data) {
+static int pakfire_linter_file_check_relro(struct pakfire_linter_file* lfile) {
int has_bind_now = 0;
GElf_Phdr phdr;
int r;
// Check if we have BIND_NOW
- r = pakfire_linter_file_elf_dyn_walk(lfile, elf,
+ r = pakfire_linter_file_elf_dyn_walk(lfile,
__pakfire_linter_file_has_bind_now, &has_bind_now);
if (r)
return r;
// Walk through all program headers
for (unsigned int i = 0;; i++) {
- if (!gelf_getphdr(elf, i, &phdr))
+ if (!gelf_getphdr(lfile->elf, i, &phdr))
break;
switch (phdr.p_type) {
return pakfire_linter_file_error(lfile, "Is not fully RELRO");
}
-static int pakfire_linter_file_check_relro(struct pakfire_linter_file* lfile) {
- return pakfire_linter_file_elf(lfile, __pakfire_linter_file_check_relro, NULL);
-}
-
/*
RPATH/RUNPATH
*/
static int __pakfire_linter_file_process_runpath(struct pakfire_linter_file* lfile,
- Elf* elf, const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
+ const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
const char* value = NULL;
const char* runpath = NULL;
char buffer[PATH_MAX];
case DT_RUNPATH:
case DT_RPATH:
// Fetch the value
- value = elf_strptr(elf, shdr->sh_link, dyn->d_un.d_val);
+ value = elf_strptr(lfile->elf, shdr->sh_link, dyn->d_un.d_val);
if (!value)
return 1;
return 0;
}
-static int __pakfire_linter_file_check_runpath(
- struct pakfire_linter_file* lfile, Elf* elf, void* data) {
- return pakfire_linter_file_elf_dyn_walk(
- lfile, elf, __pakfire_linter_file_process_runpath, data);
-}
-
static int pakfire_linter_file_check_runpath(struct pakfire_linter_file* lfile) {
- return pakfire_linter_file_elf(lfile, __pakfire_linter_file_check_runpath, NULL);
+ return pakfire_linter_file_elf_dyn_walk(
+ lfile, __pakfire_linter_file_process_runpath, NULL);
}
static uint32_t read_4_bytes(const int endianess, const char* data) {
return 0;
}
-static int pakfire_linter_file_check_cf_protection_callback(
- struct pakfire_linter_file* lfile, Elf* elf,
+static int pakfire_linter_file_check_cf_protection_callback(struct pakfire_linter_file* lfile,
const Elf_Scn* section, const GElf_Shdr* shdr, Elf_Data* data) {
GElf_Ehdr ehdr = {};
GElf_Nhdr nhdr = {};
int r;
// Fetch the ELF header
- if (!gelf_getehdr(elf, &ehdr)) {
+ if (!gelf_getehdr(lfile->elf, &ehdr)) {
ERROR(lfile->ctx, "Could not fetch the ELF header for %s: %m\n", lfile->path);
return -errno;
}
return 0;
}
-static int __pakfire_linter_file_check_cf_protection(
- struct pakfire_linter_file* lfile, Elf* elf, void* data) {
- return pakfire_linter_file_for_elf_section(
- lfile, elf, SHT_NOTE, pakfire_linter_file_check_cf_protection_callback);
-}
-
static int pakfire_linter_file_check_cf_protection(struct pakfire_linter_file* lfile) {
- return pakfire_linter_file_elf(lfile, __pakfire_linter_file_check_cf_protection, NULL);
+ return pakfire_linter_file_for_elf_section(
+ lfile, SHT_NOTE, pakfire_linter_file_check_cf_protection_callback);
}
-static int __pakfire_linter_file_is_stripped(
- struct pakfire_linter_file* lfile, Elf* elf, void* data) {
+static int pakfire_linter_file_is_stripped(struct pakfire_linter_file* lfile) {
Elf_Scn* symtab = NULL;
int r;
- // Fetch the symbol table
- r = pakfire_linter_file_get_elf_section(lfile, elf, SHT_SYMTAB, &symtab, NULL, NULL);
- if (r < 0)
- return r;
-
- // If we have found the symbol table we are not stripped
- else if (r == 0)
- return pakfire_linter_file_error(lfile, "Not Stripped");
-
- return 0;
-}
-
-static int pakfire_linter_file_is_stripped(struct pakfire_linter_file* lfile) {
switch (pakfire_linter_file_get_elf_type(lfile)) {
// Do not check Relocatable Objects
case ET_REL:
break;
}
- return pakfire_linter_file_elf(lfile, __pakfire_linter_file_is_stripped, NULL);
+ // Fetch the symbol table
+ r = pakfire_linter_file_get_elf_section(lfile, SHT_SYMTAB, &symtab, NULL, NULL);
+ if (r < 0)
+ return r;
+
+ // If we have found the symbol table we are not stripped
+ else if (r == 0)
+ return pakfire_linter_file_error(lfile, "Not Stripped");
+
+ return 0;
}
-static int __pakfire_linter_file_has_debuglink(
- struct pakfire_linter_file* lfile, Elf* elf, void* data) {
+static int pakfire_linter_file_has_debuglink(struct pakfire_linter_file* lfile) {
const char* name = NULL;
GElf_Word crc32;
// Fetch the debug link
- name = dwelf_elf_gnu_debuglink(elf, &crc32);
+ name = dwelf_elf_gnu_debuglink(lfile->elf, &crc32);
if (!name)
return pakfire_linter_file_error(lfile, "Missing Debug Link");
return 0;
}
-static int pakfire_linter_file_has_debuglink(struct pakfire_linter_file* lfile) {
- return pakfire_linter_file_elf(lfile, __pakfire_linter_file_has_debuglink, NULL);
-}
-
-static int __pakfire_linter_file_has_buildid(
- struct pakfire_linter_file* lfile, Elf* elf, void* data) {
+static int pakfire_linter_file_has_buildid(struct pakfire_linter_file* lfile) {
const void* buildid = NULL;
ssize_t length = 0;
// Fetch the build ID
- length = dwelf_elf_gnu_build_id(elf, &buildid);
+ length = dwelf_elf_gnu_build_id(lfile->elf, &buildid);
if (length < 0)
return length;
return 0;
}
-static int pakfire_linter_file_has_buildid(struct pakfire_linter_file* lfile) {
- return pakfire_linter_file_elf(lfile, __pakfire_linter_file_has_buildid, NULL);
-}
-
int pakfire_linter_file_lint(struct pakfire_linter_file* lfile) {
int r = 0;