kernelebpfbpflibbpf

BPF per CPU array is not zero initialized?


I want to use a BPF_MAP_TYPE_PERCPU_ARRAY to count the number of packets received at the SK_SKB hook. I checked the map values using bpftool map dump right after creating the map, and it seems that for some CPUs, the values are not zero initialized.

Here is the map definition:

struct {
  __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  __uint(max_entries, 1);
  __type(key, int);
  __type(value, __u64);
  __uint(pinning, LIBBPF_PIN_BY_NAME);
} request_count_map SEC(".maps");

And here is the output of bpftool map dump:

$ sudo bpftool map dump id 287
[{
        "key": 0,
        "values": [{
                "cpu": 0,
                "value": 0
            },{
                "cpu": 1,
                "value": 94322157119214
            },{
                "cpu": 2,
                "value": 140730068914171
            },{
                "cpu": 3,
                "value": 94322160575280
            },{
                "cpu": 4,
                "value": 94322160592312
            },{
                "cpu": 5,
                "value": 94322160592512
            },{
                "cpu": 6,
                "value": 80
            },{
                "cpu": 7,
                "value": 0
            },{
                "cpu": 8,
                "value": 0
            },{
                "cpu": 9,
                "value": 140730068932048
            },{
                "cpu": 10,
                "value": 0
            },{
                "cpu": 11,
                "value": 0
            },{
                "cpu": 12,
                "value": 0
            },{
                "cpu": 13,
                "value": 0
            },{
                "cpu": 14,
                "value": 0
            },{
                "cpu": 15,
                "value": 0
            },{
                "cpu": 16,
                "value": 80
            },{
                "cpu": 17,
                "value": 0
            },{
                "cpu": 18,
                "value": 0
            },{
                "cpu": 19,
                "value": 140730068932048
            }
        ]
    }
]

From the documentation (here and here), it seems that the expected behavior is for the values to be zero initialized?

Edit: I realized that I was updating the map when loading it, as follows:

int index = 0;
__u64 value = 0;

// Get the svc_identifier_map fd.
reqcnt_map_fd = bpf_obj_get(reqcnt_map_filename);

// Add the svc identifier to the svc_identifier_map.
err = bpf_map_update_elem(respcnt_map_fd, &index, &value, BPF_ANY);
if (err) {
  goto fail;
}

However, the values should still be zero?


Solution

  • When you call bpf_map_update_elem from userspace on a per-CPU map you need to provide a pointer to {value type}[__NR_CPU__] as value. In your case you provided a pointer to __u64 which is significantly smaller. So libbpf essentially read stack/memory after your value until it had enough. So you wrote part of your stack / uninitialized memory into the map.