Repository: cilium/ebpf
Pull request #549 (2022-01-25 13:02:25)

elf_reader: Fix non-determinism in determining prog type
The section prefix to types mapping was stored in a map and the type
was found by iterating over the map. Since map iteration order is
non-deterministic and there's overlapping prefixes (e.g. cgroup/sock
and cgroup/sock_create), this sometimes caused the wrong type to
be picked.

Fix this by using a slice instead and thus respecting the order in
which the types were specified.



Patch:
diff --git a/elf_reader.go b/elf_reader.go
index ac4496b..53c9758 100644
--- a/elf_reader.go
+++ b/elf_reader.go
@@ -1075,96 +1075,97 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
 }
 
 func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
-	types := map[string]struct {
+	types := []struct {
+		prefix     string
 		progType   ProgramType
 		attachType AttachType
 		progFlags  uint32
 	}{
 		// Please update the types from libbpf.c and follow the order of it.
 		// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c
-		"socket":                {SocketFilter, AttachNone, 0},
-		"sk_reuseport/migrate":  {SkReuseport, AttachSkReuseportSelectOrMigrate, 0},
-		"sk_reuseport":          {SkReuseport, AttachSkReuseportSelect, 0},
-		"kprobe/":               {Kprobe, AttachNone, 0},
-		"uprobe/":               {Kprobe, AttachNone, 0},
-		"kretprobe/":            {Kprobe, AttachNone, 0},
-		"uretprobe/":            {Kprobe, AttachNone, 0},
-		"tc":                    {SchedCLS, AttachNone, 0},
-		"classifier":            {SchedCLS, AttachNone, 0},
-		"action":                {SchedACT, AttachNone, 0},
-		"tracepoint/":           {TracePoint, AttachNone, 0},
-		"tp/":                   {TracePoint, AttachNone, 0},
-		"raw_tracepoint/":       {RawTracepoint, AttachNone, 0},
-		"raw_tp/":               {RawTracepoint, AttachNone, 0},
-		"raw_tracepoint.w/":     {RawTracepointWritable, AttachNone, 0},
-		"raw_tp.w/":             {RawTracepointWritable, AttachNone, 0},
-		"tp_btf/":               {Tracing, AttachTraceRawTp, 0},
-		"fentry/":               {Tracing, AttachTraceFEntry, 0},
-		"fmod_ret/":             {Tracing, AttachModifyReturn, 0},
-		"fexit/":                {Tracing, AttachTraceFExit, 0},
-		"fentry.s/":             {Tracing, AttachTraceFEntry, unix.BPF_F_SLEEPABLE},
-		"fmod_ret.s/":           {Tracing, AttachModifyReturn, unix.BPF_F_SLEEPABLE},
-		"fexit.s/":              {Tracing, AttachTraceFExit, unix.BPF_F_SLEEPABLE},
-		"freplace/":             {Extension, AttachNone, 0},
-		"lsm/":                  {LSM, AttachLSMMac, 0},
-		"lsm.s/":                {LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE},
-		"iter/":                 {Tracing, AttachTraceIter, 0},
-		"syscall":               {Syscall, AttachNone, 0},
-		"xdp_devmap/":           {XDP, AttachXDPDevMap, 0},
-		"xdp_cpumap/":           {XDP, AttachXDPCPUMap, 0},
-		"xdp":                   {XDP, AttachNone, 0},
-		"perf_event":            {PerfEvent, AttachNone, 0},
-		"lwt_in":                {LWTIn, AttachNone, 0},
-		"lwt_out":               {LWTOut, AttachNone, 0},
-		"lwt_xmit":              {LWTXmit, AttachNone, 0},
-		"lwt_seg6local":         {LWTSeg6Local, AttachNone, 0},
-		"cgroup_skb/ingress":    {CGroupSKB, AttachCGroupInetIngress, 0},
-		"cgroup_skb/egress":     {CGroupSKB, AttachCGroupInetEgress, 0},
-		"cgroup/skb":            {CGroupSKB, AttachNone, 0},
-		"cgroup/sock_create":    {CGroupSKB, AttachCGroupInetSockCreate, 0},
-		"cgroup/sock_release":   {CGroupSKB, AttachCgroupInetSockRelease, 0},
-		"cgroup/sock":           {CGroupSock, AttachCGroupInetSockCreate, 0},
-		"cgroup/post_bind4":     {CGroupSock, AttachCGroupInet4PostBind, 0},
-		"cgroup/post_bind6":     {CGroupSock, AttachCGroupInet6PostBind, 0},
-		"cgroup/dev":            {CGroupDevice, AttachCGroupDevice, 0},
-		"sockops":               {SockOps, AttachCGroupSockOps, 0},
-		"sk_skb/stream_parser":  {SkSKB, AttachSkSKBStreamParser, 0},
-		"sk_skb/stream_verdict": {SkSKB, AttachSkSKBStreamVerdict, 0},
-		"sk_skb":                {SkSKB, AttachNone, 0},
-		"sk_msg":                {SkMsg, AttachSkMsgVerdict, 0},
-		"lirc_mode2":            {LircMode2, AttachLircMode2, 0},
-		"flow_dissector":        {FlowDissector, AttachFlowDissector, 0},
-		"cgroup/bind4":          {CGroupSockAddr, AttachCGroupInet4Bind, 0},
-		"cgroup/bind6":          {CGroupSockAddr, AttachCGroupInet6Bind, 0},
-		"cgroup/connect4":       {CGroupSockAddr, AttachCGroupInet4Connect, 0},
-		"cgroup/connect6":       {CGroupSockAddr, AttachCGroupInet6Connect, 0},
-		"cgroup/sendmsg4":       {CGroupSockAddr, AttachCGroupUDP4Sendmsg, 0},
-		"cgroup/sendmsg6":       {CGroupSockAddr, AttachCGroupUDP6Sendmsg, 0},
-		"cgroup/recvmsg4":       {CGroupSockAddr, AttachCGroupUDP4Recvmsg, 0},
-		"cgroup/recvmsg6":       {CGroupSockAddr, AttachCGroupUDP6Recvmsg, 0},
-		"cgroup/getpeername4":   {CGroupSockAddr, AttachCgroupInet4GetPeername, 0},
-		"cgroup/getpeername6":   {CGroupSockAddr, AttachCgroupInet6GetPeername, 0},
-		"cgroup/getsockname4":   {CGroupSockAddr, AttachCgroupInet4GetSockname, 0},
-		"cgroup/getsockname6":   {CGroupSockAddr, AttachCgroupInet6GetSockname, 0},
-		"cgroup/sysctl":         {CGroupSysctl, AttachCGroupSysctl, 0},
-		"cgroup/getsockopt":     {CGroupSockopt, AttachCGroupGetsockopt, 0},
-		"cgroup/setsockopt":     {CGroupSockopt, AttachCGroupSetsockopt, 0},
-		"struct_ops+":           {StructOps, AttachNone, 0},
-		"sk_lookup/":            {SkLookup, AttachSkLookup, 0},
-
-		"seccomp": {SocketFilter, AttachNone, 0},
+		{"socket", SocketFilter, AttachNone, 0},
+		{"sk_reuseport/migrate", SkReuseport, AttachSkReuseportSelectOrMigrate, 0},
+		{"sk_reuseport", SkReuseport, AttachSkReuseportSelect, 0},
+		{"kprobe/", Kprobe, AttachNone, 0},
+		{"uprobe/", Kprobe, AttachNone, 0},
+		{"kretprobe/", Kprobe, AttachNone, 0},
+		{"uretprobe/", Kprobe, AttachNone, 0},
+		{"tc", SchedCLS, AttachNone, 0},
+		{"classifier", SchedCLS, AttachNone, 0},
+		{"action", SchedACT, AttachNone, 0},
+		{"tracepoint/", TracePoint, AttachNone, 0},
+		{"tp/", TracePoint, AttachNone, 0},
+		{"raw_tracepoint/", RawTracepoint, AttachNone, 0},
+		{"raw_tp/", RawTracepoint, AttachNone, 0},
+		{"raw_tracepoint.w/", RawTracepointWritable, AttachNone, 0},
+		{"raw_tp.w/", RawTracepointWritable, AttachNone, 0},
+		{"tp_btf/", Tracing, AttachTraceRawTp, 0},
+		{"fentry/", Tracing, AttachTraceFEntry, 0},
+		{"fmod_ret/", Tracing, AttachModifyReturn, 0},
+		{"fexit/", Tracing, AttachTraceFExit, 0},
+		{"fentry.s/", Tracing, AttachTraceFEntry, unix.BPF_F_SLEEPABLE},
+		{"fmod_ret.s/", Tracing, AttachModifyReturn, unix.BPF_F_SLEEPABLE},
+		{"fexit.s/", Tracing, AttachTraceFExit, unix.BPF_F_SLEEPABLE},
+		{"freplace/", Extension, AttachNone, 0},
+		{"lsm/", LSM, AttachLSMMac, 0},
+		{"lsm.s/", LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE},
+		{"iter/", Tracing, AttachTraceIter, 0},
+		{"syscall", Syscall, AttachNone, 0},
+		{"xdp_devmap/", XDP, AttachXDPDevMap, 0},
+		{"xdp_cpumap/", XDP, AttachXDPCPUMap, 0},
+		{"xdp", XDP, AttachNone, 0},
+		{"perf_event", PerfEvent, AttachNone, 0},
+		{"lwt_in", LWTIn, AttachNone, 0},
+		{"lwt_out", LWTOut, AttachNone, 0},
+		{"lwt_xmit", LWTXmit, AttachNone, 0},
+		{"lwt_seg6local", LWTSeg6Local, AttachNone, 0},
+		{"cgroup_skb/ingress", CGroupSKB, AttachCGroupInetIngress, 0},
+		{"cgroup_skb/egress", CGroupSKB, AttachCGroupInetEgress, 0},
+		{"cgroup/skb", CGroupSKB, AttachNone, 0},
+		{"cgroup/sock_create", CGroupSKB, AttachCGroupInetSockCreate, 0},
+		{"cgroup/sock_release", CGroupSKB, AttachCgroupInetSockRelease, 0},
+		{"cgroup/sock", CGroupSock, AttachCGroupInetSockCreate, 0},
+		{"cgroup/post_bind4", CGroupSock, AttachCGroupInet4PostBind, 0},
+		{"cgroup/post_bind6", CGroupSock, AttachCGroupInet6PostBind, 0},
+		{"cgroup/dev", CGroupDevice, AttachCGroupDevice, 0},
+		{"sockops", SockOps, AttachCGroupSockOps, 0},
+		{"sk_skb/stream_parser", SkSKB, AttachSkSKBStreamParser, 0},
+		{"sk_skb/stream_verdict", SkSKB, AttachSkSKBStreamVerdict, 0},
+		{"sk_skb", SkSKB, AttachNone, 0},
+		{"sk_msg", SkMsg, AttachSkMsgVerdict, 0},
+		{"lirc_mode2", LircMode2, AttachLircMode2, 0},
+		{"flow_dissector", FlowDissector, AttachFlowDissector, 0},
+		{"cgroup/bind4", CGroupSockAddr, AttachCGroupInet4Bind, 0},
+		{"cgroup/bind6", CGroupSockAddr, AttachCGroupInet6Bind, 0},
+		{"cgroup/connect4", CGroupSockAddr, AttachCGroupInet4Connect, 0},
+		{"cgroup/connect6", CGroupSockAddr, AttachCGroupInet6Connect, 0},
+		{"cgroup/sendmsg4", CGroupSockAddr, AttachCGroupUDP4Sendmsg, 0},
+		{"cgroup/sendmsg6", CGroupSockAddr, AttachCGroupUDP6Sendmsg, 0},
+		{"cgroup/recvmsg4", CGroupSockAddr, AttachCGroupUDP4Recvmsg, 0},
+		{"cgroup/recvmsg6", CGroupSockAddr, AttachCGroupUDP6Recvmsg, 0},
+		{"cgroup/getpeername4", CGroupSockAddr, AttachCgroupInet4GetPeername, 0},
+		{"cgroup/getpeername6", CGroupSockAddr, AttachCgroupInet6GetPeername, 0},
+		{"cgroup/getsockname4", CGroupSockAddr, AttachCgroupInet4GetSockname, 0},
+		{"cgroup/getsockname6", CGroupSockAddr, AttachCgroupInet6GetSockname, 0},
+		{"cgroup/sysctl", CGroupSysctl, AttachCGroupSysctl, 0},
+		{"cgroup/getsockopt", CGroupSockopt, AttachCGroupGetsockopt, 0},
+		{"cgroup/setsockopt", CGroupSockopt, AttachCGroupSetsockopt, 0},
+		{"struct_ops+", StructOps, AttachNone, 0},
+		{"sk_lookup/", SkLookup, AttachSkLookup, 0},
+
+		{"seccomp", SocketFilter, AttachNone, 0},
 	}
 
-	for prefix, t := range types {
-		if !strings.HasPrefix(sectionName, prefix) {
+	for _, t := range types {
+		if !strings.HasPrefix(sectionName, t.prefix) {
 			continue
 		}
 
-		if !strings.HasSuffix(prefix, "/") {
+		if !strings.HasSuffix(t.prefix, "/") {
 			return t.progType, t.attachType, t.progFlags, ""
 		}
 
-		return t.progType, t.attachType, t.progFlags, sectionName[len(prefix):]
+		return t.progType, t.attachType, t.progFlags, sectionName[len(t.prefix):]
 	}
 
 	return UnspecifiedProgram, AttachNone, 0, ""


Test patch:
diff --git a/elf_reader_test.go b/elf_reader_test.go
index f2c9daa..a0d48c7 100644
--- a/elf_reader_test.go
+++ b/elf_reader_test.go
@@ -826,6 +826,11 @@ func TestGetProgType(t *testing.T) {
 			At: AttachNone,
 			To: "",
 		},
+		"xdp_devmap/foo": {
+			Pt: XDP,
+			At: AttachXDPDevMap,
+			To: "foo",
+		},
 		"cgroup_skb/ingress": {
 			Pt: CGroupSKB,
 			At: AttachCGroupInetIngress,
@@ -847,6 +852,16 @@ func TestGetProgType(t *testing.T) {
 			At: AttachLSMMac,
 			To: "file_ioctl",
 		},
+		"sk_skb/stream_verdict/foo": {
+			Pt: SkSKB,
+			At: AttachSkSKBStreamVerdict,
+			To: "",
+		},
+		"sk_skb/bar": {
+			Pt: SkSKB,
+			At: AttachNone,
+			To: "",
+		},
 	}
 
 	for section, want := range testcases {