In the Linux kernel, the following vulnerability has been resolved:
bpf: track changespktdata property for global functions
When processing calls to certain helpers, verifier invalidates all packet pointers in a current state. For example, consider the following program:
__attribute__((__noinline__))
long skb_pull_data(struct __sk_buff *sk, __u32 len)
{
return bpf_skb_pull_data(sk, len);
}
SEC("tc")
int test_invalidate_checks(struct __sk_buff *sk)
{
int *p = (void *)(long)sk->data;
if ((void *)(p + 1) > (void *)(long)sk->data_end) return TCX_DROP;
skb_pull_data(sk, 0);
*p = 42;
return TCX_PASS;
}
After a call to bpfskbpulldata() the pointer 'p' can't be used safely. See function filter.c:bpfhelperchangespkt_data() for a list of such helpers.
At the moment verifier invalidates packet pointers when processing helper function calls, and does not traverse global sub-programs when processing calls to global sub-programs. This means that calls to helpers done from global sub-programs do not invalidate pointers in the caller state. E.g. the program above is unsafe, but is not rejected by verifier.
This commit fixes the omission by computing field bpfsubproginfo->changespktdata for each sub-program before main verification pass. changespktdata should be set if: - subprogram calls helper for which bpfhelperchangespktdata returns true; - subprogram calls a global function, for which bpfsubproginfo->changespktdata should be set.
The verifier.c:checkcfg() pass is modified to compute this information. The commit relies on depth first instruction traversal done by checkcfg() and absence of recursive function calls: - checkcfg() would eventually visit every call to subprogram S in a state when S is fully explored; - when S is fully explored: - every direct helper call within S is explored (and thus changespktdata is set if needed); - every call to subprogram S1 called by S was visited with S1 fully explored (and thus S inherits changespkt_data from S1).
The downside of such approach is that dead code elimination is not taken into account: if a helper call inside global function is dead because of current configuration, verifier would conservatively assume that the call occurs for the purpose of the changespktdata computation.
[
{
"digest": {
"length": 448.0,
"function_hash": "297280354096895661114096221933074184276"
},
"target": {
"file": "kernel/bpf/verifier.c",
"function": "visit_func_call_insn"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@51081a3f25c742da5a659d7fc6fd77ebfdd555be",
"deprecated": false,
"signature_type": "Function",
"id": "CVE-2024-58098-0d0e2a3f",
"signature_version": "v1"
},
{
"digest": {
"threshold": 0.9,
"line_hashes": [
"52284824093470831099447178676765753376",
"261361858581974102605613198465664476129",
"200505641313762809578063035334292562469",
"175531399549493799789883654816673115254"
]
},
"target": {
"file": "include/linux/bpf_verifier.h"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@51081a3f25c742da5a659d7fc6fd77ebfdd555be",
"deprecated": false,
"signature_type": "Line",
"id": "CVE-2024-58098-501cc7eb",
"signature_version": "v1"
},
{
"digest": {
"length": 1570.0,
"function_hash": "333348521390523232425304740713593168772"
},
"target": {
"file": "kernel/bpf/verifier.c",
"function": "visit_insn"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@79751e9227a5910c0e5a2c7186877d91821d957d",
"deprecated": false,
"signature_type": "Function",
"id": "CVE-2024-58098-5d59b879",
"signature_version": "v1"
},
{
"digest": {
"length": 1730.0,
"function_hash": "158887222337749801170908135126392510144"
},
"target": {
"file": "kernel/bpf/verifier.c",
"function": "check_func_call"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@51081a3f25c742da5a659d7fc6fd77ebfdd555be",
"deprecated": false,
"signature_type": "Function",
"id": "CVE-2024-58098-5f5b7557",
"signature_version": "v1"
},
{
"digest": {
"length": 1735.0,
"function_hash": "184392112503491277564962690146839999684"
},
"target": {
"file": "kernel/bpf/verifier.c",
"function": "check_func_call"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@1d572c60488b52882b719ed273767ee3b280413d",
"deprecated": false,
"signature_type": "Function",
"id": "CVE-2024-58098-64b1f981",
"signature_version": "v1"
},
{
"digest": {
"threshold": 0.9,
"line_hashes": [
"330775922854360129995506128449783364911",
"169139860711660247265806969242833475569",
"320809317568119759250696043882919789944",
"20129899727210854772669152290292556404"
]
},
"target": {
"file": "include/linux/bpf_verifier.h"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@79751e9227a5910c0e5a2c7186877d91821d957d",
"deprecated": false,
"signature_type": "Line",
"id": "CVE-2024-58098-750b2ea8",
"signature_version": "v1"
},
{
"digest": {
"threshold": 0.9,
"line_hashes": [
"106465026162770806617866549735666408349",
"320693043426728656325972073057018555858",
"171325104165703540187373692713356124320",
"252974806690749848738305026937449183127",
"129685781228347966045666954720786443815",
"337286213630885902811217975415168460751",
"313168034836195276785566480327599340883",
"149245689690554677241102811177739974897",
"290725641285484879859385254294768484187",
"257004245199321442084458541996553557496",
"258816208200982003936806775556842742377",
"221012222858821329721718618999107712090",
"137530148043012200030414728981061764676",
"162016965516736489033528955125948414993",
"83280600549578892042000537528876289709",
"138982363188168795635602618235608352519",
"333092153282623189887879295799567285761",
"40039232917883768709239162553945029715",
"37031010212905605142316017559594134407",
"97605711995622239137672370383876601606",
"15936105861748957284154227887141352332"
]
},
"target": {
"file": "kernel/bpf/verifier.c"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@1d572c60488b52882b719ed273767ee3b280413d",
"deprecated": false,
"signature_type": "Line",
"id": "CVE-2024-58098-895c2715",
"signature_version": "v1"
},
{
"digest": {
"length": 1575.0,
"function_hash": "34574149578227893996121582841813887993"
},
"target": {
"file": "kernel/bpf/verifier.c",
"function": "visit_insn"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@1d572c60488b52882b719ed273767ee3b280413d",
"deprecated": false,
"signature_type": "Function",
"id": "CVE-2024-58098-8bed6c35",
"signature_version": "v1"
},
{
"digest": {
"length": 448.0,
"function_hash": "297280354096895661114096221933074184276"
},
"target": {
"file": "kernel/bpf/verifier.c",
"function": "visit_func_call_insn"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@79751e9227a5910c0e5a2c7186877d91821d957d",
"deprecated": false,
"signature_type": "Function",
"id": "CVE-2024-58098-9c67eefc",
"signature_version": "v1"
},
{
"digest": {
"threshold": 0.9,
"line_hashes": [
"85034204048979904608592956995765980996",
"323750193802644159623735311261894641327",
"190185786498461568559255796409572626559",
"330498834169027840159544390980913043788",
"129685781228347966045666954720786443815",
"337286213630885902811217975415168460751",
"313168034836195276785566480327599340883",
"149245689690554677241102811177739974897",
"290725641285484879859385254294768484187",
"257004245199321442084458541996553557496",
"258816208200982003936806775556842742377",
"221012222858821329721718618999107712090",
"137530148043012200030414728981061764676",
"162016965516736489033528955125948414993",
"83280600549578892042000537528876289709",
"138982363188168795635602618235608352519",
"333092153282623189887879295799567285761",
"40039232917883768709239162553945029715",
"37031010212905605142316017559594134407",
"97605711995622239137672370383876601606",
"15936105861748957284154227887141352332"
]
},
"target": {
"file": "kernel/bpf/verifier.c"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@79751e9227a5910c0e5a2c7186877d91821d957d",
"deprecated": false,
"signature_type": "Line",
"id": "CVE-2024-58098-a25c7d03",
"signature_version": "v1"
},
{
"digest": {
"threshold": 0.9,
"line_hashes": [
"52284824093470831099447178676765753376",
"281146539610094791214650434600441499102",
"1919737116299986710366650769001728034",
"267627490773810335839051702758505898600"
]
},
"target": {
"file": "include/linux/bpf_verifier.h"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@1d572c60488b52882b719ed273767ee3b280413d",
"deprecated": false,
"signature_type": "Line",
"id": "CVE-2024-58098-b981b827",
"signature_version": "v1"
},
{
"digest": {
"threshold": 0.9,
"line_hashes": [
"106465026162770806617866549735666408349",
"320693043426728656325972073057018555858",
"171325104165703540187373692713356124320",
"252974806690749848738305026937449183127",
"129685781228347966045666954720786443815",
"337286213630885902811217975415168460751",
"313168034836195276785566480327599340883",
"149245689690554677241102811177739974897",
"290725641285484879859385254294768484187",
"257004245199321442084458541996553557496",
"258816208200982003936806775556842742377",
"221012222858821329721718618999107712090",
"137530148043012200030414728981061764676",
"162016965516736489033528955125948414993",
"83280600549578892042000537528876289709",
"138982363188168795635602618235608352519",
"333092153282623189887879295799567285761",
"40039232917883768709239162553945029715",
"37031010212905605142316017559594134407",
"97605711995622239137672370383876601606",
"15936105861748957284154227887141352332"
]
},
"target": {
"file": "kernel/bpf/verifier.c"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@51081a3f25c742da5a659d7fc6fd77ebfdd555be",
"deprecated": false,
"signature_type": "Line",
"id": "CVE-2024-58098-b9b0982a",
"signature_version": "v1"
},
{
"digest": {
"length": 448.0,
"function_hash": "297280354096895661114096221933074184276"
},
"target": {
"file": "kernel/bpf/verifier.c",
"function": "visit_func_call_insn"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@1d572c60488b52882b719ed273767ee3b280413d",
"deprecated": false,
"signature_type": "Function",
"id": "CVE-2024-58098-d4090db6",
"signature_version": "v1"
},
{
"digest": {
"length": 1264.0,
"function_hash": "263129774679533850730185668853380943177"
},
"target": {
"file": "kernel/bpf/verifier.c",
"function": "check_func_call"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@79751e9227a5910c0e5a2c7186877d91821d957d",
"deprecated": false,
"signature_type": "Function",
"id": "CVE-2024-58098-e6c3f896",
"signature_version": "v1"
},
{
"digest": {
"length": 1575.0,
"function_hash": "34574149578227893996121582841813887993"
},
"target": {
"file": "kernel/bpf/verifier.c",
"function": "visit_insn"
},
"source": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git@51081a3f25c742da5a659d7fc6fd77ebfdd555be",
"deprecated": false,
"signature_type": "Function",
"id": "CVE-2024-58098-ef9c4f82",
"signature_version": "v1"
}
]