Skip to contentSkip to conversation

BPF update

PATCH In review Daniel Borkmann 2 participants 4 messages Jan 12, 2016 – Jan 18, 2016

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover BPF update

Two small BPF frontend updates.

The patchset is against your current net-next branch (pre master merge).

Thanks!

Daniel Borkmann (2):
tc, bpf: check section names and type everywhere tc, bpf: more header checks on loading elf

 tc/tc_bpf.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 58 insertions(+), 6 deletions(-)
Signature · 1 line
1.9.3
#1 lore raw

PATCH 1/2 tc, bpf: check section names and type everywhere

When extracting sections, we better check for name and type. Noticed that some llvm versions emit .strtab and .shstrtab (e.g. saw it on pre 3.7), while more recent ones only seem to emit .strtab. Thus, make sure we get the right sections.

---
 tc/tc_bpf.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)
tc/tc_bpf.c +15 -6
index f9b2b00..677dd62 100644
@@ -1237,14 +1237,17 @@ static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx)
 		if (ret < 0)
 			continue;
 
-		if (!strcmp(data.sec_name, ELF_SECTION_MAPS))
+		if (data.sec_hdr.sh_type == SHT_PROGBITS &&
+		    !strcmp(data.sec_name, ELF_SECTION_MAPS))
 			ret = bpf_fetch_maps(ctx, i, &data);
-		else if (!strcmp(data.sec_name, ELF_SECTION_LICENSE))
+		else if (data.sec_hdr.sh_type == SHT_PROGBITS &&
+			 !strcmp(data.sec_name, ELF_SECTION_LICENSE))
 			ret = bpf_fetch_license(ctx, i, &data);
-		else if (data.sec_hdr.sh_type == SHT_SYMTAB)
+		else if (data.sec_hdr.sh_type == SHT_SYMTAB &&
+			 !strcmp(data.sec_name, ".symtab"))
 			ret = bpf_fetch_symtab(ctx, i, &data);
 		else if (data.sec_hdr.sh_type == SHT_STRTAB &&
-			 i != ctx->elf_hdr.e_shstrndx)
+			 !strcmp(data.sec_name, ".strtab"))
 			ret = bpf_fetch_strtab(ctx, i, &data);
 		if (ret < 0) {
 			fprintf(stderr, "Error parsing section %d! Perhaps"
@@ -1275,7 +1278,10 @@ static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section)
 			continue;
 
 		ret = bpf_fill_section_data(ctx, i, &data);
-		if (ret < 0 || strcmp(data.sec_name, section))
+		if (ret < 0 ||
+		    !(data.sec_hdr.sh_type == SHT_PROGBITS &&
+		      data.sec_hdr.sh_flags & SHF_EXECINSTR &&
+		      !strcmp(data.sec_name, section)))
 			continue;
 
 		memset(&prog, 0, sizeof(prog));
@@ -1353,7 +1359,10 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section)
 
 		idx = data_relo.sec_hdr.sh_info;
 		ret = bpf_fill_section_data(ctx, idx, &data_insn);
-		if (ret < 0 || strcmp(data_insn.sec_name, section))
+		if (ret < 0 ||
+		    !(data_insn.sec_hdr.sh_type == SHT_PROGBITS &&
+		      data_insn.sec_hdr.sh_flags & SHF_EXECINSTR &&
+		      !strcmp(data_insn.sec_name, section)))
 			continue;
 
 		ret = bpf_apply_relo_data(ctx, &data_relo, &data_insn);
Signature · 1 line
1.9.3
#2 lore raw

PATCH 2/2 tc, bpf: more header checks on loading elf

In reply to Daniel Borkmann

eBPF llvm backend can support different BPF formats, make sure the object we're trying to load matches with regards to endiannes and while at it, also check for other attributes related to BPF ELFs.

  # llc --version
  LLVM (http://llvm.org/):
    LLVM version 3.8.0svn
    Optimized build.
    Built Jan  9 2016 (02:08:10).
    Default target: x86_64-unknown-linux-gnu
    Host CPU: ivybridge

Registered Targets:
bpf - BPF (host endian)
bpfeb - BPF (big endian)
bpfel - BPF (little endian)
[...]

---
 tc/tc_bpf.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)
tc/tc_bpf.c +43 -0
index 677dd62..42c8841 100644
@@ -39,6 +39,8 @@
 #include <linux/filter.h>
 #include <linux/if_alg.h>
 
+#include <arpa/inet.h>
+
 #include "utils.h"
 
 #include "bpf_elf.h"
@@ -1564,6 +1566,38 @@ static void bpf_hash_destroy(struct bpf_elf_ctx *ctx)
 	}
 }
 
+static int bpf_elf_check_ehdr(const struct bpf_elf_ctx *ctx)
+{
+	if (ctx->elf_hdr.e_type != ET_REL ||
+	    ctx->elf_hdr.e_machine != 0 ||
+	    ctx->elf_hdr.e_version != EV_CURRENT) {
+		fprintf(stderr, "ELF format error, ELF file not for eBPF?\n");
+		return -EINVAL;
+	}
+
+	switch (ctx->elf_hdr.e_ident[EI_DATA]) {
+	default:
+		fprintf(stderr, "ELF format error, wrong endianness info?\n");
+		return -EINVAL;
+	case ELFDATA2LSB:
+		if (htons(1) == 1) {
+			fprintf(stderr,
+				"We are big endian, eBPF object is little endian!\n");
+			return -EIO;
+		}
+		break;
+	case ELFDATA2MSB:
+		if (htons(1) != 1) {
+			fprintf(stderr,
+				"We are little endian, eBPF object is big endian!\n");
+			return -EIO;
+		}
+		break;
+	}
+
+	return 0;
+}
+
 static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname,
 			    enum bpf_prog_type type, bool verbose)
 {
@@ -1587,12 +1621,21 @@ static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname,
 		goto out_fd;
 	}
 
+	if (elf_kind(ctx->elf_fd) != ELF_K_ELF) {
+		ret = -EINVAL;
+		goto out_fd;
+	}
+
 	if (gelf_getehdr(ctx->elf_fd, &ctx->elf_hdr) !=
 	    &ctx->elf_hdr) {
 		ret = -EIO;
 		goto out_elf;
 	}
 
+	ret = bpf_elf_check_ehdr(ctx);
+	if (ret < 0)
+		goto out_elf;
+
 	ctx->sec_done = calloc(ctx->elf_hdr.e_shnum,
 			       sizeof(*(ctx->sec_done)));
 	if (!ctx->sec_done) {
Signature · 1 line
1.9.3
#3 lore raw
In reply to Daniel Borkmann
Quoted 4 lines · On Tue, 12 Jan 2016 02:03:06 +0100 Daniel Borkmann <[email protected]> wrote:

Two small BPF frontend updates.

The patchset is against your current net-next branch (pre master merge).

Quoted 8 lines

Thanks!

Daniel Borkmann (2):
tc, bpf: check section names and type everywhere tc, bpf: more header checks on loading elf

 tc/tc_bpf.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 58 insertions(+), 6 deletions(-)

This applies fine to master. Accepted.