Skip to content

Commit b0a8f46

Browse files
committed
Update kprobe function handling to enforce modern signature requirements.
1 parent be582b9 commit b0a8f46

File tree

7 files changed

+74
-59
lines changed

7 files changed

+74
-59
lines changed

examples/ringbuf_on_event_demo.ks

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ var security_events : ringbuf<SecurityEvent>(8192)
4343
return XDP_PASS
4444
}
4545

46-
@kprobe fn security_monitor(ctx: *pt_regs) -> i32 {
46+
@kprobe("sys_openat") fn security_monitor(dfd: i32, filename: *u8, flags: i32, mode: u16) -> i32 {
4747
var reserved = security_events.reserve()
4848
security_events.submit(reserved)
4949
return 0

src/ebpf_c_codegen.ml

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,7 +1470,7 @@ let rec generate_c_value ?(auto_deref_map_access=false) ctx ir_val =
14701470
sprintf "({ struct %s_config *cfg = get_%s_config(); cfg ? cfg->%s : 0; })"
14711471
config_name config_name field_name
14721472
| _ -> name
1473-
(* Check if this is a kprobe function parameter in new format *)
1473+
(* Check if this is a kprobe function parameter *)
14741474
else if ctx.current_function_context_type = Some "kprobe" then
14751475
(try
14761476
(* Try to use kprobe parameter mapping to generate PT_REGS_PARM* access *)
@@ -3340,17 +3340,13 @@ let generate_c_function ctx ir_func =
33403340
in
33413341

33423342
let params_str =
3343-
(* Special handling for kprobe functions with new signature format *)
3343+
(* Special handling for kprobe functions *)
33443344
match ir_func.func_program_type with
3345-
| Some Ast.Kprobe when not (List.exists (fun (_, param_type) ->
3346-
match param_type with
3347-
| IRPointer (IRStruct ("pt_regs", _, _), _) -> true
3348-
| _ -> false
3349-
) ir_func.parameters) ->
3350-
(* New kprobe format: always use struct pt_regs *ctx parameter *)
3345+
| Some Ast.Kprobe ->
3346+
(* Kprobe functions always use struct pt_regs *ctx parameter *)
33513347
"struct pt_regs *ctx"
33523348
| _ ->
3353-
(* Traditional format: use parameters as-is *)
3349+
(* Other program types: use parameters as-is *)
33543350
String.concat ", "
33553351
(List.map (fun (name, param_type) ->
33563352
sprintf "%s %s" (ebpf_type_from_ir_type param_type) name

src/ir_function_system.ml

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,19 @@ let validate_function_signature (ir_func : ir_function) : signature_info =
4242
| _ -> false
4343
in
4444

45-
(* Check if this is a kprobe function with new signature format *)
46-
let is_kprobe_new_format = match ir_func.func_program_type with
47-
| Some Ast.Kprobe ->
48-
(* New format: parameters don't include pt_regs context *)
49-
not (List.exists (fun (_, param_type) ->
50-
match param_type with
51-
| IRPointer (IRStruct ("pt_regs", _, _), _) -> true
52-
| _ -> false
53-
) ir_func.parameters)
45+
(* Check if this is a kprobe function *)
46+
let is_kprobe_function = match ir_func.func_program_type with
47+
| Some Ast.Kprobe -> true
5448
| _ -> false
5549
in
5650

57-
if ir_func.is_main && not is_struct_ops_function && not is_kprobe_new_format then (
51+
if ir_func.is_main && not is_struct_ops_function && not is_kprobe_function then (
5852
if param_count <> 1 then
5953
errors := "Main function must have exactly one parameter (context)" :: !errors;
6054
match ir_func.parameters with
6155
| [(_, IRContext _)] -> ()
6256
| [(_, IRPointer (IRContext _, _))] -> ()
6357
| [(_, IRPointer (IRStruct ("__sk_buff", _, _), _))] -> () (* Also recognize __sk_buff as TC context *)
64-
| [(_, IRPointer (IRStruct ("pt_regs", _, _), _))] -> () (* Also recognize pt_regs as kprobe context *)
6558
| _ -> errors := "Main function parameter must be a context type" :: !errors;
6659

6760
(* Check return type based on context type *)
@@ -72,28 +65,22 @@ let validate_function_signature (ir_func : ir_function) : signature_info =
7265
| _ -> false
7366
in
7467

75-
let is_kprobe_program = match ir_func.parameters with
76-
| [(_, IRPointer (IRStruct ("pt_regs", _, _), _))] -> true (* Recognize pt_regs as kprobe *)
77-
| _ -> false
78-
in
79-
8068
match ir_func.return_type with
81-
| Some (IRAction _) when not is_tc_program && not is_kprobe_program -> () (* Action types for programs that use actions *)
82-
| Some (IRI32) when is_tc_program || is_kprobe_program -> () (* int return type for TC and kprobe programs *)
83-
| Some (IRU32) when is_tc_program || is_kprobe_program -> () (* Allow u32/int for TC and kprobe programs *)
69+
| Some (IRAction _) when not is_tc_program -> () (* Action types for programs that use actions *)
70+
| Some (IRI32) when is_tc_program -> () (* int return type for TC programs *)
71+
| Some (IRU32) when is_tc_program -> () (* Allow u32/int for TC programs *)
8472
| Some _ when is_tc_program -> errors := "TC programs must return int (i32)" :: !errors;
85-
| Some _ when is_kprobe_program -> errors := "Kprobe programs must return int (i32)" :: !errors;
86-
| Some _ -> errors := "Main function must return an action type (or int for TC/kprobe programs)" :: !errors;
73+
| Some _ -> errors := "Main function must return an action type (or int for TC programs)" :: !errors;
8774
| None -> errors := "Main function must have a return type" :: !errors
8875
);
8976

90-
(* Special validation for kprobe functions with new signature format *)
91-
if ir_func.is_main && is_kprobe_new_format then (
92-
(* Allow flexible parameter count for new kprobe format *)
77+
(* Validation for kprobe functions *)
78+
if ir_func.is_main && is_kprobe_function then (
79+
(* Kprobe functions support up to 6 parameters (kernel function signature) *)
9380
if param_count > 6 then
9481
errors := "Kprobe functions support maximum 6 parameters" :: !errors;
9582

96-
(* Validate return type for new kprobe format *)
83+
(* Validate return type for kprobe functions *)
9784
match ir_func.return_type with
9885
| Some (IRI32) -> () (* Standard kprobe return type *)
9986
| Some (IRU32) -> () (* Allow u32 as well *)

src/ir_generator.ml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2790,6 +2790,19 @@ let lower_multi_program ast symbol_table source_name =
27902790
prog_structs = [];
27912791
prog_pos = attr_func.attr_pos;
27922792
})
2793+
| AttributeWithArg (attr_name, _target_func) :: _ ->
2794+
(* Handle attributes with arguments like @kprobe("sys_read") *)
2795+
(match attr_name with
2796+
| "kprobe" ->
2797+
Some {
2798+
Ast.prog_name = attr_func.attr_function.func_name;
2799+
prog_type = Ast.Kprobe;
2800+
prog_functions = [attr_func.attr_function];
2801+
prog_maps = [];
2802+
prog_structs = [];
2803+
prog_pos = attr_func.attr_pos;
2804+
}
2805+
| _ -> None)
27932806
| _ -> None)
27942807
| _ -> None
27952808
) ast in

src/type_checker.ml

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2936,22 +2936,28 @@ let rec type_check_and_annotate_ast ?symbol_table:(provided_symbol_table=None) ?
29362936
Hashtbl.add ctx.test_functions attr_func.attr_function.func_name ();
29372937

29382938
(* Extract program type from attribute for context *)
2939-
let prog_type = match attr_func.attr_list with
2939+
let (prog_type, kprobe_target) = match attr_func.attr_list with
29402940
| SimpleAttribute prog_type_str :: _ ->
29412941
(match prog_type_str with
2942-
| "xdp" -> Some Xdp
2943-
| "tc" -> Some Tc
2944-
| "kprobe" -> Some Kprobe
2945-
| "uprobe" -> Some Uprobe
2946-
| "tracepoint" -> Some Tracepoint
2947-
| "lsm" -> Some Lsm
2948-
| "cgroup_skb" -> Some CgroupSkb
2949-
| "kfunc" -> None (* kfuncs don't have program types *)
2950-
| "private" -> None (* private functions don't have program types *)
2951-
| "helper" -> None (* helper functions don't have program types *)
2952-
| "test" -> None (* test functions don't have program types *)
2953-
| _ -> None)
2954-
| _ -> None
2942+
| "xdp" -> (Some Xdp, None)
2943+
| "tc" -> (Some Tc, None)
2944+
| "kprobe" ->
2945+
(* Reject old format: @kprobe without target function *)
2946+
type_error ("@kprobe requires target function specification. Use @kprobe(\"function_name\") instead.") attr_func.attr_pos
2947+
| "uprobe" -> (Some Uprobe, None)
2948+
| "tracepoint" -> (Some Tracepoint, None)
2949+
| "lsm" -> (Some Lsm, None)
2950+
| "cgroup_skb" -> (Some CgroupSkb, None)
2951+
| "kfunc" -> (None, None) (* kfuncs don't have program types *)
2952+
| "private" -> (None, None) (* private functions don't have program types *)
2953+
| "helper" -> (None, None) (* helper functions don't have program types *)
2954+
| "test" -> (None, None) (* test functions don't have program types *)
2955+
| _ -> (None, None))
2956+
| AttributeWithArg (attr_name, target_func) :: _ ->
2957+
(match attr_name with
2958+
| "kprobe" -> (Some Kprobe, Some target_func)
2959+
| _ -> (None, None))
2960+
| _ -> (None, None)
29552961
in
29562962

29572963
(* Validate attributed function signatures based on program type *)
@@ -3003,11 +3009,24 @@ let rec type_check_and_annotate_ast ?symbol_table:(provided_symbol_table=None) ?
30033009
| Some ret_type -> Some (resolve_user_type ctx ret_type)
30043010
| None -> None in
30053011

3006-
(* For kprobe functions, accept only the new function signature format with actual kernel function parameters *)
3007-
let valid_signature =
3008-
(* Accept any number of parameters for new format (kernel function signature) *)
3009-
List.length params >= 0 && List.length params <= 6 (* x86_64 supports max 6 function parameters *)
3010-
in
3012+
(* Validate kprobe function - only modern format supported *)
3013+
(match kprobe_target with
3014+
| Some _target_func ->
3015+
(* Modern format with target function specified *)
3016+
(* Check for invalid pt_regs parameter usage *)
3017+
List.iter (fun (_, param_type) ->
3018+
match param_type with
3019+
| Pointer (UserType "pt_regs") ->
3020+
type_error ("@kprobe functions should not use pt_regs parameter. Use kernel function parameters directly.") attr_func.attr_pos
3021+
| _ -> ()
3022+
) params;
3023+
(* Validate signature against BTF if available *)
3024+
if List.length params > 6 then
3025+
type_error ("Kprobe functions support maximum 6 parameters") attr_func.attr_pos
3026+
| None ->
3027+
(* This case should never be reached due to earlier validation *)
3028+
failwith "Internal error: kprobe without target function should have been rejected earlier"
3029+
);
30113030

30123031
(* Allow both i32 (standard eBPF kprobe return) and void (matching kernel function signature) *)
30133032
let valid_return_type = match resolved_return_type with
@@ -3017,8 +3036,8 @@ let rec type_check_and_annotate_ast ?symbol_table:(provided_symbol_table=None) ?
30173036
| _ -> false
30183037
in
30193038

3020-
if not valid_signature || not valid_return_type then
3021-
type_error ("@kprobe attributed function must have valid signature (max 6 params) with return type -> i32, u32, or void") attr_func.attr_pos
3039+
if not valid_return_type then
3040+
type_error ("@kprobe attributed function must return i32, u32, or void") attr_func.attr_pos
30223041
| Some _ -> () (* Other program types - validation can be added later *)
30233042
| None -> type_error ("Invalid or unsupported attribute") attr_func.attr_pos);
30243043

tests/test_program_ref.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn main() -> i32 {
4747
(** Test program reference with different program types *)
4848
let test_different_program_types () =
4949
let program_text = {|
50-
@kprobe fn kprobe_tracer(ctx: *pt_regs) -> i32 {
50+
@kprobe("sys_read") fn kprobe_tracer(fd: u32, buf: *u8, count: usize) -> i32 {
5151
return 0
5252
}
5353

tests/test_ringbuf.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ var security_events : ringbuf<SecurityEvent>(8192)
459459
return XDP_PASS
460460
}
461461

462-
@kprobe fn security_prog(ctx: *pt_regs) -> i32 {
462+
@kprobe("sys_read") fn security_prog(fd: u32, buf: *u8, count: usize) -> i32 {
463463
var sec_event = security_events.reserve()
464464
if (sec_event != null) {
465465
security_events.submit(sec_event)
@@ -1043,7 +1043,7 @@ fn handle_security(event: *SecurityEvent) -> i32 {
10431043
return XDP_PASS
10441044
}
10451045

1046-
@kprobe fn security_monitor(ctx: *pt_regs) -> i32 {
1046+
@kprobe("sys_openat") fn security_monitor(dfd: i32, filename: *u8, flags: i32, mode: u16) -> i32 {
10471047
var sec_event = security_events.reserve()
10481048
if (sec_event != null) {
10491049
sec_event->severity = 1

0 commit comments

Comments
 (0)