|
@@ -63,393 +63,203 @@ struct
|
|
|
// volatile const u64 request_host_pos;
|
|
// volatile const u64 request_host_pos;
|
|
|
// volatile const u64 request_proto_pos;
|
|
// volatile const u64 request_proto_pos;
|
|
|
|
|
|
|
|
-static __always_inline long inject_header(void* headers_ptr, struct span_context* propagated_ctx) {
|
|
|
|
|
- bpf_printk("11111111111111");
|
|
|
|
|
- // Read the key-value count - this field must be the first one in the hmap struct as documented in src/runtime/map.go
|
|
|
|
|
- u64 curr_keyvalue_count = 0;
|
|
|
|
|
- long res = bpf_probe_read_user(&curr_keyvalue_count, sizeof(curr_keyvalue_count), headers_ptr);
|
|
|
|
|
-
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Couldn't read map key-value count from user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (curr_keyvalue_count >= 8) {
|
|
|
|
|
- cw_bpf_debug("Map size is bigger than 8, skipping context propagation");
|
|
|
|
|
|
|
+// cw_inject_header_half: 准备 header 注入数据,保存到 bucket_map_value,由后续的 go_update_header 完成实际注入
|
|
|
|
|
+// 支持 Go 1.24+ Swiss Tables 和旧版本的 hmap
|
|
|
|
|
+//
|
|
|
|
|
+// 流程说明:
|
|
|
|
|
+// 1. uprobe_Transport_roundTrip 调用 cw_inject_header_half,准备数据
|
|
|
|
|
+// 2. bpf_tail_call 调用 go_update_header,完成实际注入
|
|
|
|
|
+//
|
|
|
|
|
+// Swiss Tables 结构说明(Go 1.24+):
|
|
|
|
|
+// - maps.Map.used (offset 0): 元素数量
|
|
|
|
|
+// - maps.Map.dirPtr (offset 16): 指向 group (小 map) 或 directory (大 map)
|
|
|
|
|
+// - maps.Map.dirLen (offset 24): 0 表示小 map,>0 表示大 map
|
|
|
|
|
+// - group: ctrlGroup (8 bytes) + slots[8] (每个 slot 40 bytes: string 16 + []string 24)
|
|
|
|
|
+
|
|
|
|
|
+// cw_inject_header_half: 准备 header 注入数据,保存到 bucket_map_value,由后续的 go_update_header 完成实际注入
|
|
|
|
|
+// 支持 Go 1.24+ Swiss Tables 和旧版本的 hmap
|
|
|
|
|
+static __always_inline long cw_inject_header_half(void* headers_ptr, char * header_str,struct ebpf_proc_info* proc_info) {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: START");
|
|
|
|
|
+
|
|
|
|
|
+ if (!proc_info) {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: proc_info is NULL");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Get pointer to temp bucket struct we store in a map (avoiding large local variable on the stack)
|
|
// Get pointer to temp bucket struct we store in a map (avoiding large local variable on the stack)
|
|
|
- // Performing read-modify-write on the bucket
|
|
|
|
|
- u32 map_id = 1;
|
|
|
|
|
|
|
+ u32 map_id = CLIENT_MAP_KEY;
|
|
|
struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
|
|
struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
|
|
|
if (!bucket_map_value) {
|
|
if (!bucket_map_value) {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Failed to get bucket_map_value");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
- __builtin_memset(bucket_map_value, 0, sizeof(struct map_bucket));
|
|
|
|
|
|
|
+ __builtin_memset(bucket_map_value, 0, sizeof(struct map_bucket));
|
|
|
|
|
|
|
|
- __u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
|
|
|
- __u32 tgid = pid_tgid >> 32;
|
|
|
|
|
- struct ebpf_proc_info *proc_info =
|
|
|
|
|
- bpf_map_lookup_elem(&proc_info_map, &tgid);
|
|
|
|
|
- if(!proc_info)
|
|
|
|
|
- {
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void *buckets_ptr_ptr = (void*) (headers_ptr + proc_info->buckets_ptr_pos);
|
|
|
|
|
- void *bucket_ptr = 0; // The actual pointer to the buckets
|
|
|
|
|
-
|
|
|
|
|
- if (curr_keyvalue_count == 0) {
|
|
|
|
|
- bpf_printk("curr_keyvalue_count == 0");
|
|
|
|
|
-
|
|
|
|
|
- // No key-value pairs in the Go map, need to "allocate" memory for the user
|
|
|
|
|
- bucket_ptr = write_target_data(bucket_map_value, sizeof(struct map_bucket));
|
|
|
|
|
- if (bucket_ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write bucket to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
- // Update the buckets pointer in the hmap struct to point to newly allocated bucket
|
|
|
|
|
- res = bpf_probe_write_user(buckets_ptr_ptr, &bucket_ptr, sizeof(bucket_ptr));
|
|
|
|
|
|
|
+ // Check if Go version >= 1.24 (Swiss Tables)
|
|
|
|
|
+ if (proc_info->version >= GO_VERSION(1, 24, 0)) {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Go 1.24+ Swiss Tables detected");
|
|
|
|
|
+
|
|
|
|
|
+ // Read used count (first field in maps.Map)
|
|
|
|
|
+ u64 used = 0;
|
|
|
|
|
+ long res = bpf_probe_read_user(&used, sizeof(used), headers_ptr);
|
|
|
if (res < 0) {
|
|
if (res < 0) {
|
|
|
- cw_bpf_debug("Failed to update the map bucket pointer for the user");
|
|
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Failed to read used count, res=%ld", res);
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
- } else {
|
|
|
|
|
- // There is at least 1 key-value pair, hence the bucket pointer from the user is valid
|
|
|
|
|
- // Read the bucket pointer
|
|
|
|
|
- res = bpf_probe_read_user(&bucket_ptr, sizeof(bucket_ptr), buckets_ptr_ptr);
|
|
|
|
|
- // Read the user's bucket to the eBPF map entry
|
|
|
|
|
- bpf_probe_read_user(bucket_map_value, sizeof(struct map_bucket), bucket_ptr);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- u8 bucket_index = curr_keyvalue_count & 0x7;
|
|
|
|
|
- bpf_printk("bucket_index:%d",bucket_index);
|
|
|
|
|
-
|
|
|
|
|
- char traceparent_tophash = 0xee;
|
|
|
|
|
- bucket_map_value->tophash[bucket_index] = traceparent_tophash;
|
|
|
|
|
-
|
|
|
|
|
- // Prepare the key string for the user
|
|
|
|
|
- char key[W3C_KEY_LENGTH] = "traceparent";
|
|
|
|
|
- void *ptr = write_target_data(key, W3C_KEY_LENGTH);
|
|
|
|
|
- if (ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write key to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
- bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = W3C_KEY_LENGTH, .str = ptr};
|
|
|
|
|
-
|
|
|
|
|
- // Prepare the value string slice
|
|
|
|
|
- // First the value string which constains the span context
|
|
|
|
|
- char val[W3C_VAL_LENGTH];
|
|
|
|
|
- span_context_to_w3c_string(propagated_ctx, val);
|
|
|
|
|
- ptr = write_target_data(val, sizeof(val));
|
|
|
|
|
- if(ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write value to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // The go string pointing to the above val
|
|
|
|
|
- struct go_string_ot header_value = {.len = W3C_VAL_LENGTH, .str = ptr};
|
|
|
|
|
- ptr = write_target_data((void*)&header_value, sizeof(header_value));
|
|
|
|
|
- if(ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write go_string to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Last, go_slice pointing to the above go_string
|
|
|
|
|
- bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};
|
|
|
|
|
-
|
|
|
|
|
- // Update the map header count field
|
|
|
|
|
- curr_keyvalue_count += 1;
|
|
|
|
|
- res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Failed to update key-value count in map header");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Update the bucket
|
|
|
|
|
- res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Failed to update bucket content");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
|
|
|
|
|
- return 0;
|
|
|
|
|
-}
|
|
|
|
|
-// 00:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
|
|
|
|
|
-static __always_inline long cw_inject_header(void* headers_ptr, struct apm_span_context* propagated_ctx) {
|
|
|
|
|
- // Read the key-value count - this field must be the first one in the hmap struct as documented in src/runtime/map.go
|
|
|
|
|
- u64 curr_keyvalue_count = 0;
|
|
|
|
|
- long res = bpf_probe_read_user(&curr_keyvalue_count, sizeof(curr_keyvalue_count), headers_ptr);
|
|
|
|
|
-
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Couldn't read map key-value count from user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (curr_keyvalue_count >= 8) {
|
|
|
|
|
- cw_bpf_debug("Map size is bigger than 8, skipping context propagation");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Get pointer to temp bucket struct we store in a map (avoiding large local variable on the stack)
|
|
|
|
|
- // Performing read-modify-write on the bucket
|
|
|
|
|
- u32 map_id = 0;
|
|
|
|
|
- struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
|
|
|
|
|
- if (!bucket_map_value) {
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- __u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
|
|
|
- __u32 tgid = pid_tgid >> 32;
|
|
|
|
|
- struct ebpf_proc_info *proc_info =
|
|
|
|
|
- bpf_map_lookup_elem(&proc_info_map, &tgid);
|
|
|
|
|
- if(!proc_info)
|
|
|
|
|
- {
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void *buckets_ptr_ptr = (void*) (headers_ptr + proc_info->buckets_ptr_pos);
|
|
|
|
|
- void *bucket_ptr = 0; // The actual pointer to the buckets
|
|
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: used=%llu", used);
|
|
|
|
|
|
|
|
- if (curr_keyvalue_count == 0) {
|
|
|
|
|
- // No key-value pairs in the Go map, need to "allocate" memory for the user
|
|
|
|
|
- bucket_ptr = write_target_data(bucket_map_value, sizeof(struct map_bucket));
|
|
|
|
|
- if (bucket_ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write bucket to user");
|
|
|
|
|
|
|
+ if (used >= 8) {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Map is full (used=%llu)", used);
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
- // Update the buckets pointer in the hmap struct to point to newly allocated bucket
|
|
|
|
|
- res = bpf_probe_write_user(buckets_ptr_ptr, &bucket_ptr, sizeof(bucket_ptr));
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // Read dirLen (at offset 24)
|
|
|
|
|
+ s32 dirLen = 0;
|
|
|
|
|
+ res = bpf_probe_read_user(&dirLen, sizeof(dirLen), (void*)(headers_ptr + 24));
|
|
|
if (res < 0) {
|
|
if (res < 0) {
|
|
|
- cw_bpf_debug("Failed to update the map bucket pointer for the user");
|
|
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Failed to read dirLen, res=%ld", res);
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
- } else {
|
|
|
|
|
- // There is at least 1 key-value pair, hence the bucket pointer from the user is valid
|
|
|
|
|
- // Read the bucket pointer
|
|
|
|
|
- res = bpf_probe_read_user(&bucket_ptr, sizeof(bucket_ptr), buckets_ptr_ptr);
|
|
|
|
|
- // Read the user's bucket to the eBPF map entry
|
|
|
|
|
- bpf_probe_read_user(bucket_map_value, sizeof(struct map_bucket), bucket_ptr);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- u8 bucket_index = curr_keyvalue_count & 0x7;
|
|
|
|
|
-
|
|
|
|
|
- char traceparent_tophash = 0xee;
|
|
|
|
|
- bucket_map_value->tophash[bucket_index] = traceparent_tophash;
|
|
|
|
|
-
|
|
|
|
|
- // Prepare the key string for the user
|
|
|
|
|
- char key[W3C_KEY_LENGTH] = "traceparent";
|
|
|
|
|
- void *ptr = write_target_data(key, W3C_KEY_LENGTH);
|
|
|
|
|
- if (ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write key to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
- bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = W3C_KEY_LENGTH, .str = ptr};
|
|
|
|
|
-
|
|
|
|
|
- // Prepare the value string slice
|
|
|
|
|
- // First the value string which constains the span context
|
|
|
|
|
- char val[CW_HEADER_LENGTH];
|
|
|
|
|
- span_context_to_cw_string(propagated_ctx, val);
|
|
|
|
|
- ptr = write_target_data(val, sizeof(val));
|
|
|
|
|
- if(ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write value to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // The go string pointing to the above val
|
|
|
|
|
- struct go_string_ot header_value = {.len = CW_HEADER_LENGTH, .str = ptr};
|
|
|
|
|
- ptr = write_target_data((void*)&header_value, sizeof(header_value));
|
|
|
|
|
- if(ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write go_string to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Last, go_slice pointing to the above go_string
|
|
|
|
|
- bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};
|
|
|
|
|
-
|
|
|
|
|
- // Update the map header count field
|
|
|
|
|
- curr_keyvalue_count += 1;
|
|
|
|
|
- res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Failed to update key-value count in map header");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Update the bucket
|
|
|
|
|
- res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Failed to update bucket content");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
|
|
|
|
|
- return 0;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 00:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
|
|
|
|
|
-static __always_inline long cw_inject_header2(void* headers_ptr, struct apm_span_context* propagated_ctx) {
|
|
|
|
|
- // Read the key-value count - this field must be the first one in the hmap struct as documented in src/runtime/map.go
|
|
|
|
|
- u64 curr_keyvalue_count = 0;
|
|
|
|
|
- long res = bpf_probe_read_user(&curr_keyvalue_count, sizeof(curr_keyvalue_count), headers_ptr);
|
|
|
|
|
-
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Couldn't read map key-value count from user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (curr_keyvalue_count >= 8) {
|
|
|
|
|
- cw_bpf_debug("Map size is bigger than 8, skipping context propagation");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Get pointer to temp bucket struct we store in a map (avoiding large local variable on the stack)
|
|
|
|
|
- // Performing read-modify-write on the bucket
|
|
|
|
|
- u32 map_id = 0;
|
|
|
|
|
- struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
|
|
|
|
|
- if (!bucket_map_value) {
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
- __u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
|
|
|
- __u32 tgid = pid_tgid >> 32;
|
|
|
|
|
- struct ebpf_proc_info *proc_info =
|
|
|
|
|
- bpf_map_lookup_elem(&proc_info_map, &tgid);
|
|
|
|
|
- if(!proc_info)
|
|
|
|
|
- {
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- void *buckets_ptr_ptr = (void*) (headers_ptr + proc_info->buckets_ptr_pos);
|
|
|
|
|
- void *bucket_ptr = 0; // The actual pointer to the buckets
|
|
|
|
|
-
|
|
|
|
|
- if (curr_keyvalue_count == 0) {
|
|
|
|
|
- // No key-value pairs in the Go map, need to "allocate" memory for the user
|
|
|
|
|
- bucket_ptr = write_target_data(bucket_map_value, sizeof(struct map_bucket));
|
|
|
|
|
- if (bucket_ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write bucket to user");
|
|
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: dirLen=%d", dirLen);
|
|
|
|
|
+
|
|
|
|
|
+ void *group_ptr = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ if (dirLen == 0) {
|
|
|
|
|
+ // Small map: dirPtr points directly to a single group
|
|
|
|
|
+ void *dirPtr_ptr = (void*)(headers_ptr + proc_info->buckets_ptr_pos);
|
|
|
|
|
+ res = bpf_probe_read_user(&group_ptr, sizeof(group_ptr), dirPtr_ptr);
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Failed to read dirPtr, res=%ld", res);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (group_ptr == NULL) {
|
|
|
|
|
+ // Empty map: need to allocate a new group
|
|
|
|
|
+ // Group structure: ctrlGroup (8 bytes) + slots[8] (each slot 40 bytes = 320 bytes total)
|
|
|
|
|
+ // Total: 8 + 320 = 328 bytes
|
|
|
|
|
+ // We'll allocate in chunks to avoid stack overflow
|
|
|
|
|
+ // First allocate and write control word (8 bytes)
|
|
|
|
|
+ u64 empty_ctrls = 0x8080808080808080ULL;
|
|
|
|
|
+ group_ptr = cw_write_target_data(&empty_ctrls, sizeof(empty_ctrls), proc_info);
|
|
|
|
|
+ if (group_ptr == NULL) {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Failed to allocate group");
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Initialize slots area (320 bytes) with zeros
|
|
|
|
|
+ // Write in 8-byte chunks: 320 / 8 = 40 chunks
|
|
|
|
|
+ u64 zero = 0;
|
|
|
|
|
+ for (int i = 1; i <= 40; i++) {
|
|
|
|
|
+ void *chunk_ptr = (void*)((u64)group_ptr + (i * 8));
|
|
|
|
|
+ res = bpf_probe_write_user(chunk_ptr, &zero, sizeof(zero));
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Failed to init chunk %d, res=%ld", i, res);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Allocated new group at %p", group_ptr);
|
|
|
|
|
+
|
|
|
|
|
+ // Update dirPtr in the map to point to the new group
|
|
|
|
|
+ res = bpf_probe_write_user(dirPtr_ptr, &group_ptr, sizeof(group_ptr));
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Failed to update dirPtr, res=%ld", res);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Updated dirPtr");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: group_ptr=%p (existing)", group_ptr);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Large map (dirLen=%d) not supported yet", dirLen);
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
- // Update the buckets pointer in the hmap struct to point to newly allocated bucket
|
|
|
|
|
- res = bpf_probe_write_user(buckets_ptr_ptr, &bucket_ptr, sizeof(bucket_ptr));
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // Read control word to find empty slot
|
|
|
|
|
+ u64 ctrls = 0;
|
|
|
|
|
+ res = bpf_probe_read_user(&ctrls, sizeof(ctrls), group_ptr);
|
|
|
if (res < 0) {
|
|
if (res < 0) {
|
|
|
- cw_bpf_debug("Failed to update the map bucket pointer for the user");
|
|
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Failed to read control word, res=%ld", res);
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
- } else {
|
|
|
|
|
- // There is at least 1 key-value pair, hence the bucket pointer from the user is valid
|
|
|
|
|
- // Read the bucket pointer
|
|
|
|
|
- res = bpf_probe_read_user(&bucket_ptr, sizeof(bucket_ptr), buckets_ptr_ptr);
|
|
|
|
|
- // Read the user's bucket to the eBPF map entry
|
|
|
|
|
- bpf_probe_read_user(bucket_map_value, sizeof(struct map_bucket), bucket_ptr);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- u8 bucket_index = curr_keyvalue_count & 0x7;
|
|
|
|
|
-
|
|
|
|
|
-// char traceparent_tophash = 0xee;
|
|
|
|
|
-// bucket_map_value->tophash[bucket_index] = traceparent_tophash;
|
|
|
|
|
-
|
|
|
|
|
- // Prepare the key string for the user
|
|
|
|
|
- char key[CW_HEADER_KEY_LENGTH] = CW_HEADER_KEY_VAL;
|
|
|
|
|
- void *ptr = write_target_data(key, CW_HEADER_KEY_LENGTH);
|
|
|
|
|
- if (ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write key to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
- bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};
|
|
|
|
|
-
|
|
|
|
|
- char traceparent_tophash = 0xee;
|
|
|
|
|
- bucket_map_value->tophash[bucket_index] = traceparent_tophash;
|
|
|
|
|
- bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- // Prepare the value string slice
|
|
|
|
|
- // First the value string which constains the span context
|
|
|
|
|
- char val[CW_HEADER_VAL_LENGTH];
|
|
|
|
|
- span_context_to_cw_string(propagated_ctx, val);
|
|
|
|
|
- ptr = write_target_data(val, sizeof(val));
|
|
|
|
|
- if(ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write value to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // The go string pointing to the above val
|
|
|
|
|
- struct go_string_ot header_value = {.len = CW_HEADER_VAL_LENGTH, .str = ptr};
|
|
|
|
|
- ptr = write_target_data((void*)&header_value, sizeof(header_value));
|
|
|
|
|
- if(ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write go_string to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Last, go_slice pointing to the above go_string
|
|
|
|
|
- bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};
|
|
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: ctrls=0x%llx", ctrls);
|
|
|
|
|
+
|
|
|
|
|
+ // Find first empty slot (ctrl byte = 0x80)
|
|
|
|
|
+ u8 empty_ctrl = 0x80;
|
|
|
|
|
+ u8 slot_idx = 0;
|
|
|
|
|
+ bool found_empty = false;
|
|
|
|
|
+
|
|
|
|
|
+ for (u8 i = 0; i < 8; i++) {
|
|
|
|
|
+ u8 ctrl_byte = (u8)((ctrls >> (i * 8)) & 0xFF);
|
|
|
|
|
+ if (ctrl_byte == empty_ctrl) {
|
|
|
|
|
+ slot_idx = i;
|
|
|
|
|
+ found_empty = true;
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Found empty slot at index %d", i);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Update the map header count field
|
|
|
|
|
- curr_keyvalue_count += 1;
|
|
|
|
|
- res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Failed to update key-value count in map header");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!found_empty) {
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: No empty slot found (ctrls=0x%llx)", ctrls);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Update the bucket
|
|
|
|
|
- res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Failed to update bucket content");
|
|
|
|
|
- return -1;
|
|
|
|
|
|
|
+ // Save information for go_update_header
|
|
|
|
|
+ // For Swiss Tables, bucket_ptr stores group_ptr, bucket_index stores slot_idx
|
|
|
|
|
+ bucket_map_value->headers_ptr = headers_ptr;
|
|
|
|
|
+ bucket_map_value->bucket_ptr = group_ptr; // Store group_ptr instead of bucket_ptr
|
|
|
|
|
+ bucket_map_value->curr_keyvalue_count = used; // Store used count
|
|
|
|
|
+ bucket_map_value->bucket_index = slot_idx; // Store slot index
|
|
|
|
|
+
|
|
|
|
|
+ // Copy header_str to bucket_map_value
|
|
|
|
|
+ // Note: header_str is a local array in uprobe_Transport_roundTrip, we need to copy it
|
|
|
|
|
+ // Use __builtin_memcpy instead of bpf_probe_read for local-to-local copy
|
|
|
|
|
+ __builtin_memcpy(bucket_map_value->header_str, header_str, CW_HEADER_VAL_LENGTH);
|
|
|
|
|
+
|
|
|
|
|
+ // Quick verification: check first 3 bytes
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: copied[0-2]=0x%02x 0x%02x 0x%02x",
|
|
|
|
|
+ (u8)bucket_map_value->header_str[0],
|
|
|
|
|
+ (u8)bucket_map_value->header_str[1],
|
|
|
|
|
+ (u8)bucket_map_value->header_str[2]);
|
|
|
|
|
+
|
|
|
|
|
+ // Mark as Swiss Tables by setting a special flag (we'll use bucket_index >= 8 as flag)
|
|
|
|
|
+ // Actually, we can use a different approach - store dirLen in bucket_index
|
|
|
|
|
+ // For now, we'll use bucket_index as slot_idx (0-7), and check version in go_update_header
|
|
|
|
|
+
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: SUCCESS - saved info for Swiss Tables, slot_idx=%d", slot_idx);
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
|
|
|
|
|
- return 0;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 00:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
|
|
|
|
|
-static __always_inline long cw_inject_header_half(void* headers_ptr, char * header_str,struct ebpf_proc_info* proc_info) {
|
|
|
|
|
- // Read the key-value count - this field must be the first one in the hmap struct as documented in src/runtime/map.go
|
|
|
|
|
|
|
+ // Old implementation for Go < 1.24
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Using old hmap implementation");
|
|
|
|
|
+
|
|
|
|
|
+ // Read the key-value count - this field must be the first one in the hmap struct
|
|
|
u64 curr_keyvalue_count = 0;
|
|
u64 curr_keyvalue_count = 0;
|
|
|
long res = bpf_probe_read_user(&curr_keyvalue_count, sizeof(curr_keyvalue_count), headers_ptr);
|
|
long res = bpf_probe_read_user(&curr_keyvalue_count, sizeof(curr_keyvalue_count), headers_ptr);
|
|
|
-
|
|
|
|
|
if (res < 0) {
|
|
if (res < 0) {
|
|
|
- cw_bpf_debug("Couldn't read map key-value count from user");
|
|
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Couldn't read map key-value count, res=%ld", res);
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (curr_keyvalue_count >= 8) {
|
|
if (curr_keyvalue_count >= 8) {
|
|
|
- cw_bpf_debug("Map size is bigger than 8, skipping context propagation");
|
|
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Map size is bigger than 8, skipping");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Get pointer to temp bucket struct we store in a map (avoiding large local variable on the stack)
|
|
|
|
|
- // Performing read-modify-write on the bucket
|
|
|
|
|
- u32 map_id = CLIENT_MAP_KEY;
|
|
|
|
|
- struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
|
|
|
|
|
- if (!bucket_map_value) {
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
- __builtin_memset(bucket_map_value, 0, sizeof(struct map_bucket));
|
|
|
|
|
-// __u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
|
|
|
-// __u32 tgid = pid_tgid >> 32;
|
|
|
|
|
-// struct ebpf_proc_info *proc_info =
|
|
|
|
|
-// bpf_map_lookup_elem(&proc_info_map, &tgid);
|
|
|
|
|
-// if(!proc_info)
|
|
|
|
|
-// {
|
|
|
|
|
-// return -1;
|
|
|
|
|
-// }
|
|
|
|
|
-
|
|
|
|
|
void *buckets_ptr_ptr = (void*) (headers_ptr + proc_info->buckets_ptr_pos);
|
|
void *buckets_ptr_ptr = (void*) (headers_ptr + proc_info->buckets_ptr_pos);
|
|
|
- void *bucket_ptr = 0; // The actual pointer to the buckets
|
|
|
|
|
|
|
+ void *bucket_ptr = 0;
|
|
|
|
|
|
|
|
if (curr_keyvalue_count == 0) {
|
|
if (curr_keyvalue_count == 0) {
|
|
|
// No key-value pairs in the Go map, need to "allocate" memory for the user
|
|
// No key-value pairs in the Go map, need to "allocate" memory for the user
|
|
|
- bucket_ptr = cw_write_target_data(bucket_map_value, sizeof(struct map_bucket),proc_info);
|
|
|
|
|
|
|
+ bucket_ptr = cw_write_target_data(bucket_map_value, sizeof(struct map_bucket), proc_info);
|
|
|
if (bucket_ptr == NULL) {
|
|
if (bucket_ptr == NULL) {
|
|
|
- cw_bpf_debug("inject_header: Failed to write bucket to user");
|
|
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Failed to write bucket to user");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
// Update the buckets pointer in the hmap struct to point to newly allocated bucket
|
|
// Update the buckets pointer in the hmap struct to point to newly allocated bucket
|
|
|
res = bpf_probe_write_user(buckets_ptr_ptr, &bucket_ptr, sizeof(bucket_ptr));
|
|
res = bpf_probe_write_user(buckets_ptr_ptr, &bucket_ptr, sizeof(bucket_ptr));
|
|
|
if (res < 0) {
|
|
if (res < 0) {
|
|
|
- cw_bpf_debug("Failed to update the map bucket pointer for the user");
|
|
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: Failed to update bucket pointer, res=%ld", res);
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
@@ -462,87 +272,13 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
|
|
|
|
|
|
|
|
u8 bucket_index = curr_keyvalue_count & 0x7;
|
|
u8 bucket_index = curr_keyvalue_count & 0x7;
|
|
|
|
|
|
|
|
-// bucket_map_value->header_value_str_p = ptr;
|
|
|
|
|
-
|
|
|
|
|
- bucket_map_value->headers_ptr = headers_ptr;
|
|
|
|
|
- bucket_map_value->bucket_ptr = bucket_ptr;
|
|
|
|
|
-
|
|
|
|
|
- bucket_map_value->curr_keyvalue_count = curr_keyvalue_count;
|
|
|
|
|
- bucket_map_value->bucket_index = bucket_index;
|
|
|
|
|
- bpf_probe_read(bucket_map_value->header_str, sizeof(bucket_map_value->header_str),header_str);
|
|
|
|
|
- cw_bpf_debug("bucket_map_value->header_str %s",bucket_map_value->header_str);
|
|
|
|
|
-// bucket_map_value->header_str = header_str;
|
|
|
|
|
-
|
|
|
|
|
-// void * header_str_ptr = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH,proc_info);
|
|
|
|
|
-// if(header_str_ptr == NULL) {
|
|
|
|
|
-// cw_bpf_debug("inject_header: Failed to write value to user");
|
|
|
|
|
-// return -1;
|
|
|
|
|
-// }
|
|
|
|
|
-// bucket_map_value->header_str_p = header_str;
|
|
|
|
|
-
|
|
|
|
|
- return 0;
|
|
|
|
|
-
|
|
|
|
|
-// char traceparent_tophash = 0xee;
|
|
|
|
|
-// bucket_map_value->tophash[bucket_index] = traceparent_tophash;
|
|
|
|
|
-
|
|
|
|
|
- // Prepare the key string for the user
|
|
|
|
|
- char key[CW_HEADER_KEY_LENGTH] = CW_HEADER_KEY_VAL;
|
|
|
|
|
- void *ptr = cw_write_target_data(key, CW_HEADER_KEY_LENGTH,proc_info);
|
|
|
|
|
- if (ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write key to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-// bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};
|
|
|
|
|
-
|
|
|
|
|
- char traceparent_tophash = 0xee;
|
|
|
|
|
- bucket_map_value->tophash[bucket_index] = traceparent_tophash;
|
|
|
|
|
- bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};
|
|
|
|
|
-
|
|
|
|
|
-// u32 k0;
|
|
|
|
|
-// struct tail_client_ctx_t *tail_calls_context = bpf_map_lookup_elem(&tail_client_ctx_heap, &k0);
|
|
|
|
|
-// if (!tail_calls_context){
|
|
|
|
|
-// return -1;
|
|
|
|
|
-// }
|
|
|
|
|
-
|
|
|
|
|
- // Prepare the value string slice
|
|
|
|
|
- // First the value string which constains the span context
|
|
|
|
|
-// char val[CW_HEADER_VAL_LENGTH];
|
|
|
|
|
-// span_context_to_cw_string(propagated_ctx, val);
|
|
|
|
|
-// 往前提
|
|
|
|
|
- ptr = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH,proc_info);
|
|
|
|
|
- if(ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write value to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-// return 0;
|
|
|
|
|
- // The go string pointing to the above val
|
|
|
|
|
- struct go_string_ot header_value = {.len = CW_HEADER_VAL_LENGTH, .str = ptr};
|
|
|
|
|
- ptr = cw_write_target_data((void*)&header_value, sizeof(header_value),proc_info);
|
|
|
|
|
- if(ptr == NULL) {
|
|
|
|
|
- cw_bpf_debug("inject_header: Failed to write go_string to user");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Last, go_slice pointing to the above go_string
|
|
|
|
|
- bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};
|
|
|
|
|
-
|
|
|
|
|
- // Update the map header count field
|
|
|
|
|
- curr_keyvalue_count += 1;
|
|
|
|
|
- res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Failed to update key-value count in map header");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Update the bucket
|
|
|
|
|
- res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
|
|
|
|
|
- if (res < 0) {
|
|
|
|
|
- cw_bpf_debug("Failed to update bucket content");
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
|
|
|
|
|
|
|
+ bucket_map_value->headers_ptr = headers_ptr;
|
|
|
|
|
+ bucket_map_value->bucket_ptr = bucket_ptr;
|
|
|
|
|
+ bucket_map_value->curr_keyvalue_count = curr_keyvalue_count;
|
|
|
|
|
+ bucket_map_value->bucket_index = bucket_index;
|
|
|
|
|
+ bpf_probe_read(bucket_map_value->header_str, sizeof(bucket_map_value->header_str), header_str);
|
|
|
|
|
+
|
|
|
|
|
+ bpf_printk("cw_inject_header_half: SUCCESS - saved info for old hmap, bucket_index=%d", bucket_index);
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -550,7 +286,7 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
|
|
|
// func net/http/transport.roundTrip(req *Request) (*Response, error)
|
|
// func net/http/transport.roundTrip(req *Request) (*Response, error)
|
|
|
SEC("uprobe/Transport_roundTrip")
|
|
SEC("uprobe/Transport_roundTrip")
|
|
|
int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
|
|
int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
|
|
|
- cw_bpf_debug("--------[Uprobe HTTP Client] start %llu",get_current_goroutine());
|
|
|
|
|
|
|
+ bpf_printk("--------[Uprobe HTTP Client] start %llu",get_current_goroutine());
|
|
|
|
|
|
|
|
u64 request_pos = 2;
|
|
u64 request_pos = 2;
|
|
|
void *req_ptr = get_argument(ctx, request_pos);
|
|
void *req_ptr = get_argument(ctx, request_pos);
|
|
@@ -688,7 +424,19 @@ int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
|
|
|
// cw_bpf_debug("uprobe_Transport_roundTrip: Failed to inject header");
|
|
// cw_bpf_debug("uprobe_Transport_roundTrip: Failed to inject header");
|
|
|
// }
|
|
// }
|
|
|
char val[CW_HEADER_VAL_LENGTH];
|
|
char val[CW_HEADER_VAL_LENGTH];
|
|
|
|
|
+ __builtin_memset(val, 0, sizeof(val)); // Initialize to zero
|
|
|
span_context_to_cw_string(&httpReq->apm_sc, val);
|
|
span_context_to_cw_string(&httpReq->apm_sc, val);
|
|
|
|
|
+
|
|
|
|
|
+ // Verify val content after generation - check first few bytes as hex
|
|
|
|
|
+ bpf_printk("uprobe_Transport_roundTrip: val[0]=0x%02x, val[1]=0x%02x, val[2]=0x%02x",
|
|
|
|
|
+ (u8)val[0], (u8)val[1], (u8)val[2]);
|
|
|
|
|
+ bpf_printk("uprobe_Transport_roundTrip: val[3]=0x%02x, val[4]=0x%02x, val[5]=0x%02x",
|
|
|
|
|
+ (u8)val[3], (u8)val[4], (u8)val[5]);
|
|
|
|
|
+
|
|
|
|
|
+ // Also verify as characters if printable
|
|
|
|
|
+ if (val[0] >= 32 && val[0] < 127) {
|
|
|
|
|
+ bpf_printk("uprobe_Transport_roundTrip: val[0-2] as chars: %c%c%c", val[0], val[1], val[2]);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
long res2 = cw_inject_header_half(headers_ptr, val,proc_info);
|
|
long res2 = cw_inject_header_half(headers_ptr, val,proc_info);
|
|
|
if (res2 < 0) {
|
|
if (res2 < 0) {
|
|
@@ -708,115 +456,488 @@ int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// bpf_prog_up__go_update_header
|
|
|
|
|
|
|
+// bpf_prog_up__go_update_header: 完成实际的 header 注入
|
|
|
|
|
+// 从 bucket_map_value 读取信息,写入到 Go map 中
|
|
|
PROGUP(go_update_header)(struct pt_regs *ctx) {
|
|
PROGUP(go_update_header)(struct pt_regs *ctx) {
|
|
|
|
|
+ bpf_printk("go_update_header: START");
|
|
|
|
|
+
|
|
|
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
|
__u32 tgid = pid_tgid >> 32;
|
|
__u32 tgid = pid_tgid >> 32;
|
|
|
struct ebpf_proc_info *proc_info =
|
|
struct ebpf_proc_info *proc_info =
|
|
|
bpf_map_lookup_elem(&proc_info_map, &tgid);
|
|
bpf_map_lookup_elem(&proc_info_map, &tgid);
|
|
|
if(!proc_info)
|
|
if(!proc_info)
|
|
|
{
|
|
{
|
|
|
|
|
+ bpf_printk("go_update_header: proc_info is NULL");
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
-// __u32 k0;
|
|
|
|
|
-// struct tail_client_ctx_t *tail_calls_context =
|
|
|
|
|
-// bpf_map_lookup_elem(&tail_client_ctx_heap, &k0);
|
|
|
|
|
-// if (!tail_calls_context){
|
|
|
|
|
-// return -1;
|
|
|
|
|
-// }
|
|
|
|
|
- u32 map_id = CLIENT_MAP_KEY;
|
|
|
|
|
|
|
|
|
|
|
|
+ u32 map_id = CLIENT_MAP_KEY;
|
|
|
struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
|
|
struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
|
|
|
if (!bucket_map_value) {
|
|
if (!bucket_map_value) {
|
|
|
|
|
+ bpf_printk("go_update_header: bucket_map_value is NULL");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
-// if (!bucket_map_value->header_value_str_p){
|
|
|
|
|
-// return -1;
|
|
|
|
|
-// }
|
|
|
|
|
|
|
+
|
|
|
if (!bucket_map_value->headers_ptr){
|
|
if (!bucket_map_value->headers_ptr){
|
|
|
|
|
+ bpf_printk("go_update_header: headers_ptr is NULL");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
if (!bucket_map_value->bucket_ptr){
|
|
if (!bucket_map_value->bucket_ptr){
|
|
|
|
|
+ bpf_printk("go_update_header: bucket_ptr is NULL");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
-// if (!bucket_map_value->header_str){
|
|
|
|
|
-// return -1;
|
|
|
|
|
-// }
|
|
|
|
|
-// if (!bucket_map_value->header_str_p){
|
|
|
|
|
-// return -1;
|
|
|
|
|
-// }
|
|
|
|
|
- if (bucket_map_value->bucket_index >=8) {
|
|
|
|
|
|
|
+ if (bucket_map_value->bucket_index >= 8) {
|
|
|
|
|
+ bpf_printk("go_update_header: bucket_index >= 8");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void *headers_ptr = bucket_map_value->headers_ptr;
|
|
void *headers_ptr = bucket_map_value->headers_ptr;
|
|
|
- void *bucket_ptr = bucket_map_value->bucket_ptr;
|
|
|
|
|
-
|
|
|
|
|
-// u8 bucket_index = 0;
|
|
|
|
|
-// bucket_index = bucket_map_value->bucket_index;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ void *bucket_ptr = bucket_map_value->bucket_ptr; // For old hmap: bucket_ptr, For Swiss Tables: group_ptr
|
|
|
u64 curr_keyvalue_count = bucket_map_value->curr_keyvalue_count;
|
|
u64 curr_keyvalue_count = bucket_map_value->curr_keyvalue_count;
|
|
|
char * header_str = bucket_map_value->header_str;
|
|
char * header_str = bucket_map_value->header_str;
|
|
|
|
|
+ u8 bucket_index = bucket_map_value->bucket_index; // For old hmap: bucket_index, For Swiss Tables: slot_idx
|
|
|
|
|
+
|
|
|
|
|
+ bpf_printk("go_update_header: headers_ptr=%p", headers_ptr);
|
|
|
|
|
+ bpf_printk("go_update_header: bucket_ptr=%p, count=%llu", bucket_ptr, curr_keyvalue_count);
|
|
|
|
|
+ bpf_printk("go_update_header: bucket_index=%d", bucket_index);
|
|
|
|
|
+
|
|
|
|
|
+ // Verify header_str content before using it - check first 6 bytes
|
|
|
|
|
+ bpf_printk("go_update_header: header_str[0-2]=0x%02x 0x%02x 0x%02x",
|
|
|
|
|
+ (u8)header_str[0], (u8)header_str[1], (u8)header_str[2]);
|
|
|
|
|
+ bpf_printk("go_update_header: header_str[3-5]=0x%02x 0x%02x 0x%02x",
|
|
|
|
|
+ (u8)header_str[3], (u8)header_str[4], (u8)header_str[5]);
|
|
|
|
|
+
|
|
|
|
|
+ // Check if Go version >= 1.24 (Swiss Tables)
|
|
|
|
|
+ if (proc_info->version >= GO_VERSION(1, 24, 0)) {
|
|
|
|
|
+ bpf_printk("go_update_header: Go 1.24+ Swiss Tables - injecting into group");
|
|
|
|
|
+
|
|
|
|
|
+ // For Swiss Tables, bucket_ptr is actually group_ptr, bucket_index is slot_idx
|
|
|
|
|
+ void *group_ptr = bucket_ptr;
|
|
|
|
|
+ u8 slot_idx = bucket_index;
|
|
|
|
|
+
|
|
|
|
|
+ // Prepare key "cwtrace"
|
|
|
|
|
+ // Note: Go strings don't include null terminator, so len is exactly 7
|
|
|
|
|
+ char key[8] = "cwtrace"; // 7 chars + null terminator for C string
|
|
|
|
|
+ void *key_str_ptr = cw_write_target_data(key, CW_HEADER_KEY_LENGTH, proc_info);
|
|
|
|
|
+ if (key_str_ptr == NULL) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to write key");
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ bpf_printk("go_update_header: key_str_ptr=%p", key_str_ptr);
|
|
|
|
|
+
|
|
|
|
|
+ // Save key_str_ptr to a volatile variable to prevent compiler optimization
|
|
|
|
|
+ // Use multiple steps to force compiler to use correct value
|
|
|
|
|
+ void *key_str_ptr_copy = key_str_ptr;
|
|
|
|
|
+ volatile void *key_str_ptr_volatile = key_str_ptr_copy;
|
|
|
|
|
+ u64 saved_key_str_ptr_early = (u64)(void*)key_str_ptr_volatile;
|
|
|
|
|
+
|
|
|
|
|
+ bpf_printk("go_update_header: saved_key_str_ptr_early=0x%llx", saved_key_str_ptr_early);
|
|
|
|
|
+
|
|
|
|
|
+ // Verify the saved value is not NULL and not equal to any future slot_ptr_u64 value
|
|
|
|
|
+ // We can't check against slot_ptr_u64 yet, but we can check it's not zero
|
|
|
|
|
+ if (saved_key_str_ptr_early == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: ERROR: saved_key_str_ptr_early is NULL!");
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Double-check by reading back from key_str_ptr
|
|
|
|
|
+ void *key_str_ptr_verify = key_str_ptr;
|
|
|
|
|
+ u64 saved_verify = (u64)key_str_ptr_verify;
|
|
|
|
|
+ if (saved_key_str_ptr_early != saved_verify) {
|
|
|
|
|
+ bpf_printk("go_update_header: ERROR: saved_key_str_ptr_early mismatch!");
|
|
|
|
|
+ bpf_printk("go_update_header: saved=0x%llx, verify=0x%llx", saved_key_str_ptr_early, saved_verify);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Prepare value string
|
|
|
|
|
+ // Verify header_str content before writing
|
|
|
|
|
+ bpf_printk("go_update_header: Before write, header_str[0-2]=0x%02x 0x%02x 0x%02x",
|
|
|
|
|
+ (u8)header_str[0], (u8)header_str[1], (u8)header_str[2]);
|
|
|
|
|
+ bpf_printk("go_update_header: Before write, header_str[3-5]=0x%02x 0x%02x 0x%02x",
|
|
|
|
|
+ (u8)header_str[3], (u8)header_str[4], (u8)header_str[5]);
|
|
|
|
|
+
|
|
|
|
|
+ void *header_str_ptr = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH, proc_info);
|
|
|
|
|
+ if(header_str_ptr == NULL) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to write header_str");
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ // Save header_str_ptr to u64 immediately and verify it's correct
|
|
|
|
|
+ // Use the same technique as key_str_ptr to avoid register corruption
|
|
|
|
|
+ void *header_str_ptr_copy = header_str_ptr;
|
|
|
|
|
+ volatile void *header_str_ptr_volatile = header_str_ptr_copy;
|
|
|
|
|
+ u64 saved_header_str_ptr_u64 = (u64)(void*)header_str_ptr_volatile;
|
|
|
|
|
+
|
|
|
|
|
+ // Verify immediately
|
|
|
|
|
+ u64 verify_immediate = (u64)header_str_ptr;
|
|
|
|
|
+ if (saved_header_str_ptr_u64 != verify_immediate) {
|
|
|
|
|
+ bpf_printk("go_update_header: ERROR: saved_header_str_ptr_u64 mismatch at save!");
|
|
|
|
|
+ bpf_printk("go_update_header: saved=0x%llx, verify=0x%llx", saved_header_str_ptr_u64, verify_immediate);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bpf_printk("go_update_header: header_str_ptr=%p", header_str_ptr);
|
|
|
|
|
+ bpf_printk("go_update_header: saved_header_str_ptr_u64=0x%llx", saved_header_str_ptr_u64);
|
|
|
|
|
+
|
|
|
|
|
+ // Verify what was written to userspace using both pointers
|
|
|
|
|
+ char verify_header_str_saved[8] = {0};
|
|
|
|
|
+ long verify_res_saved = bpf_probe_read_user(verify_header_str_saved, sizeof(verify_header_str_saved), (void*)saved_header_str_ptr_u64);
|
|
|
|
|
+ if (verify_res_saved == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: From saved_ptr, [0-2]=0x%02x 0x%02x 0x%02x",
|
|
|
|
|
+ (u8)verify_header_str_saved[0], (u8)verify_header_str_saved[1], (u8)verify_header_str_saved[2]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ char verify_header_str_orig[8] = {0};
|
|
|
|
|
+ long verify_res_orig = bpf_probe_read_user(verify_header_str_orig, sizeof(verify_header_str_orig), header_str_ptr);
|
|
|
|
|
+ if (verify_res_orig == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: From orig_ptr, [0-2]=0x%02x 0x%02x 0x%02x",
|
|
|
|
|
+ (u8)verify_header_str_orig[0], (u8)verify_header_str_orig[1], (u8)verify_header_str_orig[2]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Create go_string_ot for the value using saved pointer
|
|
|
|
|
+ struct go_string_ot val_str = {.str = (void*)saved_header_str_ptr_u64, .len = CW_HEADER_VAL_LENGTH};
|
|
|
|
|
+ void *val_str_struct_ptr = cw_write_target_data((void*)&val_str, sizeof(val_str), proc_info);
|
|
|
|
|
+ if(val_str_struct_ptr == NULL) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to write val_str struct");
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ bpf_printk("go_update_header: val_str_struct_ptr=%p", val_str_struct_ptr);
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate slot offset
|
|
|
|
|
+ // Group layout: ctrlGroup (8 bytes) + slots[8]
|
|
|
|
|
+ // For map[string][]string:
|
|
|
|
|
+ // - key: string (16 bytes: ptr 8 + len 8)
|
|
|
|
|
+ // - elem: []string (24 bytes: array 8 + len 8 + cap 8)
|
|
|
|
|
+ // - slot size: 16 + 24 = 40 bytes
|
|
|
|
|
+ // Note: Go structs are aligned, but for map[string][]string, the slot should be exactly 40 bytes
|
|
|
|
|
+ u64 group_slots_offset = 8; // After ctrlGroup (8 bytes)
|
|
|
|
|
+ u64 slot_size = 40; // string (16) + []string (24)
|
|
|
|
|
+ u64 slot_offset = group_slots_offset + (slot_idx * slot_size);
|
|
|
|
|
+
|
|
|
|
|
+ bpf_printk("go_update_header: slot_idx=%d", slot_idx);
|
|
|
|
|
+ bpf_printk("go_update_header: group_slots_offset=%llu", group_slots_offset);
|
|
|
|
|
+ bpf_printk("go_update_header: slot_size=%llu", slot_size);
|
|
|
|
|
+ bpf_printk("go_update_header: slot_offset=%llu", slot_offset);
|
|
|
|
|
+ bpf_printk("go_update_header: group_ptr=%p", group_ptr);
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate slot_ptr carefully to avoid any issues
|
|
|
|
|
+ u64 group_ptr_u64 = (u64)group_ptr;
|
|
|
|
|
+ u64 slot_ptr_u64 = group_ptr_u64 + slot_offset;
|
|
|
|
|
+
|
|
|
|
|
+ bpf_printk("go_update_header: group_ptr_u64=0x%llx", group_ptr_u64);
|
|
|
|
|
+ bpf_printk("go_update_header: slot_ptr_u64=0x%llx", slot_ptr_u64);
|
|
|
|
|
+
|
|
|
|
|
+ // Verify slot_ptr is within reasonable bounds (should be >= group_ptr + 8 and < group_ptr + 328)
|
|
|
|
|
+ if (slot_ptr_u64 < group_ptr_u64 + 8 || slot_ptr_u64 >= group_ptr_u64 + 328) {
|
|
|
|
|
+ bpf_printk("go_update_header: slot_ptr out of bounds!");
|
|
|
|
|
+ bpf_printk("go_update_header: group_ptr_u64=0x%llx, slot_ptr_u64=0x%llx", group_ptr_u64, slot_ptr_u64);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Write key (go_string_ot at slot offset 0)
|
|
|
|
|
+ // Verify key_str_ptr is valid
|
|
|
|
|
+ if (key_str_ptr == NULL) {
|
|
|
|
|
+ bpf_printk("go_update_header: key_str_ptr is NULL!");
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Verify key string data is valid before writing
|
|
|
|
|
+ char key_check[8] = {0};
|
|
|
|
|
+ long res = bpf_probe_read_user(key_check, sizeof(key_check), key_str_ptr);
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to verify key string data, res=%ld", res);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ bpf_printk("go_update_header: key_str_ptr=%p", key_str_ptr);
|
|
|
|
|
+ bpf_printk("go_update_header: key_check[0]=0x%x", (u8)key_check[0]);
|
|
|
|
|
+
|
|
|
|
|
+ // Create key_str struct and verify it's correct before writing
|
|
|
|
|
+ struct go_string_ot key_str = {.str = key_str_ptr, .len = CW_HEADER_KEY_LENGTH};
|
|
|
|
|
+ bpf_printk("go_update_header: Writing key: str=%p, len=%d", key_str.str, key_str.len);
|
|
|
|
|
+
|
|
|
|
|
+ // Verify key_str is still correct right before writing
|
|
|
|
|
+ if (key_str.str != key_str_ptr || key_str.len != CW_HEADER_KEY_LENGTH) {
|
|
|
|
|
+ bpf_printk("go_update_header: ERROR: key_str corrupted before write!");
|
|
|
|
|
+ bpf_printk("go_update_header: key_str.str=%p, expected=%p", key_str.str, key_str_ptr);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Read what's currently in the slot before writing (for debugging)
|
|
|
|
|
+ // Use (void*)slot_ptr_u64 directly to avoid variable corruption
|
|
|
|
|
+ struct go_string_ot slot_before = {0};
|
|
|
|
|
+ res = bpf_probe_read_user(&slot_before, sizeof(slot_before), (void*)slot_ptr_u64);
|
|
|
|
|
+ if (res == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Slot before write: str=%p", slot_before.str);
|
|
|
|
|
+ bpf_printk("go_update_header: Slot before write: len=%lld", slot_before.len);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Write key directly using slot_ptr_u64 - write pointer and length separately to avoid corruption
|
|
|
|
|
+ // Re-read key_str_ptr from the bucket_map_value to get the correct value
|
|
|
|
|
+ // This is a workaround for eBPF compiler register corruption issues
|
|
|
|
|
+ char key_recreate[8] = "cwtrace";
|
|
|
|
|
+ void *key_str_ptr_fresh = cw_write_target_data(key_recreate, CW_HEADER_KEY_LENGTH, proc_info);
|
|
|
|
|
+ if (key_str_ptr_fresh == NULL) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to recreate key string");
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ u64 key_str_ptr_u64 = (u64)key_str_ptr_fresh;
|
|
|
|
|
+
|
|
|
|
|
+ u64 saved_key_str_len = (u64)CW_HEADER_KEY_LENGTH;
|
|
|
|
|
+
|
|
|
|
|
+ bpf_printk("go_update_header: key_str_ptr_fresh=%p, u64=0x%llx", key_str_ptr_fresh, key_str_ptr_u64);
|
|
|
|
|
+ bpf_printk("go_update_header: saved_key_str_len=%llu", saved_key_str_len);
|
|
|
|
|
+ bpf_printk("go_update_header: Writing key pointer: 0x%llx to slot at 0x%llx", key_str_ptr_u64, slot_ptr_u64);
|
|
|
|
|
+
|
|
|
|
|
+ // Write pointer first (first 8 bytes of go_string_ot) - use fresh value
|
|
|
|
|
+ res = bpf_probe_write_user((void*)slot_ptr_u64, &key_str_ptr_u64, sizeof(key_str_ptr_u64));
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to write key pointer, res=%ld", res);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Verify pointer was written correctly
|
|
|
|
|
+ u64 verify_ptr = 0;
|
|
|
|
|
+ res = bpf_probe_read_user(&verify_ptr, sizeof(verify_ptr), (void*)slot_ptr_u64);
|
|
|
|
|
+ if (res == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Verified pointer after write: 0x%llx", verify_ptr);
|
|
|
|
|
+ if (verify_ptr != key_str_ptr_u64) {
|
|
|
|
|
+ bpf_printk("go_update_header: ERROR: Pointer mismatch!");
|
|
|
|
|
+ bpf_printk("go_update_header: Expected 0x%llx, got 0x%llx", key_str_ptr_u64, verify_ptr);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Write length second (next 8 bytes of go_string_ot)
|
|
|
|
|
+ u64 slot_len_ptr = slot_ptr_u64 + 8;
|
|
|
|
|
+ bpf_printk("go_update_header: Writing key length: %llu to slot at 0x%llx", saved_key_str_len, slot_len_ptr);
|
|
|
|
|
+ res = bpf_probe_write_user((void*)slot_len_ptr, &saved_key_str_len, sizeof(saved_key_str_len));
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to write key length, res=%ld", res);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ bpf_printk("go_update_header: Key written to slot");
|
|
|
|
|
+
|
|
|
|
|
+ // Verify what we wrote - use slot_ptr_u64 directly
|
|
|
|
|
+ u64 slot_ptr_for_verify = slot_ptr_u64;
|
|
|
|
|
+ struct go_string_ot verify_key = {0};
|
|
|
|
|
+ res = bpf_probe_read_user(&verify_key, sizeof(verify_key), (void*)slot_ptr_for_verify);
|
|
|
|
|
+ if (res == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Verified key: str=%p, len=%lld", verify_key.str, verify_key.len);
|
|
|
|
|
+ bpf_printk("go_update_header: Verify read from 0x%llx", slot_ptr_for_verify);
|
|
|
|
|
+ if (verify_key.str != key_str_ptr_fresh || verify_key.len != CW_HEADER_KEY_LENGTH) {
|
|
|
|
|
+ bpf_printk("go_update_header: Key verification failed!");
|
|
|
|
|
+ bpf_printk("go_update_header: Expected str=%p, len=%d", key_str_ptr_fresh, CW_HEADER_KEY_LENGTH);
|
|
|
|
|
+ bpf_printk("go_update_header: Got str=%p, len=%lld", verify_key.str, verify_key.len);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Also verify the actual key string content
|
|
|
|
|
+ char key_content[8] = {0};
|
|
|
|
|
+ res = bpf_probe_read_user(key_content, sizeof(key_content), verify_key.str);
|
|
|
|
|
+ if (res == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Key content[0-2]: %c%c%c", key_content[0], key_content[1], key_content[2]);
|
|
|
|
|
+ bpf_printk("go_update_header: Key content[3-4]: %c%c", key_content[3], key_content[4]);
|
|
|
|
|
+ bpf_printk("go_update_header: Key content[5-6]: %c%c", key_content[5], key_content[6]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Read the entire slot to see what Go runtime will see
|
|
|
|
|
+ // Read as go_string_ot first, then verify the bytes
|
|
|
|
|
+ u64 slot_ptr_for_read = slot_ptr_u64;
|
|
|
|
|
+ bpf_printk("go_update_header: Reading slot at 0x%llx", slot_ptr_for_read);
|
|
|
|
|
+ struct go_string_ot slot_key_verify = {0};
|
|
|
|
|
+ res = bpf_probe_read_user(&slot_key_verify, sizeof(slot_key_verify), (void*)slot_ptr_for_read);
|
|
|
|
|
+ if (res == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Slot key as struct: str=%p, len=%lld", slot_key_verify.str, slot_key_verify.len);
|
|
|
|
|
+ bpf_printk("go_update_header: Expected: str=%p, len=%d", key_str_ptr_fresh, CW_HEADER_KEY_LENGTH);
|
|
|
|
|
+ if (slot_key_verify.str != key_str_ptr_fresh || slot_key_verify.len != CW_HEADER_KEY_LENGTH) {
|
|
|
|
|
+ bpf_printk("go_update_header: WARNING: Slot content mismatch!");
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to read slot_key_verify, res=%ld", res);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Also read raw bytes for debugging - use slot_key_verify we already read
|
|
|
|
|
+ bpf_printk("go_update_header: Slot raw pointer from struct: 0x%llx", (u64)slot_key_verify.str);
|
|
|
|
|
+ bpf_printk("go_update_header: Slot raw length from struct: 0x%llx", (u64)slot_key_verify.len);
|
|
|
|
|
+
|
|
|
|
|
+ // Read raw bytes to see what's actually in memory
|
|
|
|
|
+ char slot_raw[16] = {0}; // Only read first 16 bytes (go_string_ot)
|
|
|
|
|
+ res = bpf_probe_read_user(slot_raw, sizeof(slot_raw), (void*)slot_ptr_for_read);
|
|
|
|
|
+ if (res == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Slot raw bytes (first 16 bytes):");
|
|
|
|
|
+ for (int i = 0; i < 16; i++) {
|
|
|
|
|
+ bpf_printk("go_update_header: slot[%d]=0x%02x", i, (u8)slot_raw[i]);
|
|
|
|
|
+ }
|
|
|
|
|
+ // Verify first 8 bytes match the pointer we wrote
|
|
|
|
|
+ u64 *raw_ptr = (u64*)slot_raw;
|
|
|
|
|
+ bpf_printk("go_update_header: First 8 bytes as u64: 0x%llx", raw_ptr[0]);
|
|
|
|
|
+ bpf_printk("go_update_header: Expected pointer: 0x%llx", key_str_ptr_u64);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to verify key, res=%ld", res);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-// cw_bpf_debug("header_str %s",bucket_map_value->header_str);
|
|
|
|
|
|
|
+ // Write value (go_slice_ot at slot offset 16, after key)
|
|
|
|
|
+ // Verify elem_ptr is within bounds
|
|
|
|
|
+ u64 elem_ptr_u64 = slot_ptr_u64 + 16; // After key (16 bytes)
|
|
|
|
|
+ if (elem_ptr_u64 < group_ptr_u64 + 8 || elem_ptr_u64 >= group_ptr_u64 + 328) {
|
|
|
|
|
+ bpf_printk("go_update_header: elem_ptr out of bounds!");
|
|
|
|
|
+ bpf_printk("go_update_header: elem_ptr_u64=0x%llx", elem_ptr_u64);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ bpf_printk("go_update_header: elem_ptr_u64=0x%llx", elem_ptr_u64);
|
|
|
|
|
+
|
|
|
|
|
+ // Re-create value string struct to avoid register corruption (similar to key fix)
|
|
|
|
|
+ // Re-read header_str from map to get the correct pointer value
|
|
|
|
|
+ // Since saved_header_str_ptr_u64 might be corrupted, we'll re-read from the map
|
|
|
|
|
+ // But actually, we already have header_str_ptr from the map, so let's use that directly
|
|
|
|
|
+ // However, header_str_ptr might also be corrupted by now, so we need to re-read header_str
|
|
|
|
|
+ // and write it again to get a fresh pointer
|
|
|
|
|
+
|
|
|
|
|
+ // Re-write header_str to get a fresh pointer (similar to key fix)
|
|
|
|
|
+ void *header_str_ptr_fresh = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH, proc_info);
|
|
|
|
|
+ if (header_str_ptr_fresh == NULL) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to recreate header_str");
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ u64 header_str_ptr_fresh_u64 = (u64)header_str_ptr_fresh;
|
|
|
|
|
+ bpf_printk("go_update_header: header_str_ptr_fresh=%p, u64=0x%llx", header_str_ptr_fresh, header_str_ptr_fresh_u64);
|
|
|
|
|
+
|
|
|
|
|
+ // Use fresh pointer to create val_str struct
|
|
|
|
|
+ struct go_string_ot val_str_fresh = {.str = (void*)header_str_ptr_fresh_u64, .len = CW_HEADER_VAL_LENGTH};
|
|
|
|
|
+ void *val_str_struct_ptr_fresh = cw_write_target_data((void*)&val_str_fresh, sizeof(val_str_fresh), proc_info);
|
|
|
|
|
+ if (val_str_struct_ptr_fresh == NULL) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to recreate val_str struct");
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ u64 val_str_struct_ptr_u64 = (u64)val_str_struct_ptr_fresh;
|
|
|
|
|
+ bpf_printk("go_update_header: val_str_struct_ptr_fresh=%p, u64=0x%llx", val_str_struct_ptr_fresh, val_str_struct_ptr_u64);
|
|
|
|
|
+
|
|
|
|
|
+ struct go_slice_ot val_slice = {.array = (void*)val_str_struct_ptr_u64, .len = 1, .cap = 1};
|
|
|
|
|
+ bpf_printk("go_update_header: Writing value slice: array=%p, len=%d, cap=%d", val_slice.array, val_slice.len, val_slice.cap);
|
|
|
|
|
+ // Use elem_ptr_u64 directly to avoid variable corruption
|
|
|
|
|
+ res = bpf_probe_write_user((void*)elem_ptr_u64, &val_slice, sizeof(val_slice));
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to write value slice, res=%ld", res);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ bpf_printk("go_update_header: Value written to slot");
|
|
|
|
|
+
|
|
|
|
|
+ // Verify value was written correctly
|
|
|
|
|
+ struct go_slice_ot verify_val = {0};
|
|
|
|
|
+ res = bpf_probe_read_user(&verify_val, sizeof(verify_val), (void*)elem_ptr_u64);
|
|
|
|
|
+ if (res == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Verified value: array=%p, len=%lld, cap=%lld", verify_val.array, verify_val.len, verify_val.cap);
|
|
|
|
|
+ if (verify_val.array != (void*)val_str_struct_ptr_u64 || verify_val.len != 1 || verify_val.cap != 1) {
|
|
|
|
|
+ bpf_printk("go_update_header: Value verification failed!");
|
|
|
|
|
+ bpf_printk("go_update_header: Expected array=%p, got array=%p", (void*)val_str_struct_ptr_u64, verify_val.array);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Also verify the actual string content in val_str_struct_ptr
|
|
|
|
|
+ struct go_string_ot verify_val_str = {0};
|
|
|
|
|
+ res = bpf_probe_read_user(&verify_val_str, sizeof(verify_val_str), verify_val.array);
|
|
|
|
|
+ if (res == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Value string: str=%p, len=%lld", verify_val_str.str, verify_val_str.len);
|
|
|
|
|
+ if (verify_val_str.str != (void*)header_str_ptr_fresh_u64) {
|
|
|
|
|
+ bpf_printk("go_update_header: WARNING: Value string pointer mismatch!");
|
|
|
|
|
+ bpf_printk("go_update_header: Expected str=%p, got str=%p", (void*)header_str_ptr_fresh_u64, verify_val_str.str);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Verify the actual string content
|
|
|
|
|
+ char verify_str_content[8] = {0};
|
|
|
|
|
+ res = bpf_probe_read_user(verify_str_content, sizeof(verify_str_content), verify_val_str.str);
|
|
|
|
|
+ if (res == 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Value string content[0-2]=0x%02x 0x%02x 0x%02x",
|
|
|
|
|
+ (u8)verify_str_content[0], (u8)verify_str_content[1], (u8)verify_str_content[2]);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ // Update control byte: set to H2 hash (lower 7 bits of hash)
|
|
|
|
|
+ // For simplicity, use a fixed value (0x5A) that's not 0x80 (empty) or 0xFE (deleted)
|
|
|
|
|
+ u8 new_ctrl = 0x5A; // Placeholder H2 hash
|
|
|
|
|
+
|
|
|
|
|
+ // Read current control word
|
|
|
|
|
+ u64 ctrls = 0;
|
|
|
|
|
+ res = bpf_probe_read_user(&ctrls, sizeof(ctrls), group_ptr);
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to read control word, res=%ld", res);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Update control byte in the control word
|
|
|
|
|
+ u64 ctrl_mask = 0xFFULL << (slot_idx * 8);
|
|
|
|
|
+ u64 new_ctrl_value = ((u64)new_ctrl) << (slot_idx * 8);
|
|
|
|
|
+ ctrls = (ctrls & ~ctrl_mask) | new_ctrl_value;
|
|
|
|
|
+ bpf_printk("go_update_header: Updating ctrl, slot_idx=%d, new_ctrl=0x%x", slot_idx, new_ctrl);
|
|
|
|
|
+
|
|
|
|
|
+ res = bpf_probe_write_user(group_ptr, &ctrls, sizeof(ctrls));
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to update control word, res=%ld", res);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ bpf_printk("go_update_header: Control word updated");
|
|
|
|
|
+
|
|
|
|
|
+ // Update used count
|
|
|
|
|
+ u64 used = curr_keyvalue_count + 1;
|
|
|
|
|
+ res = bpf_probe_write_user(headers_ptr, &used, sizeof(used));
|
|
|
|
|
+ if (res < 0) {
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to update used count, res=%ld", res);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ bpf_printk("go_update_header: Used count updated to %llu", used);
|
|
|
|
|
+
|
|
|
|
|
+ bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
|
|
|
|
|
+ bpf_printk("go_update_header: SUCCESS - Swiss Tables injection completed");
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ // Old implementation for Go < 1.24
|
|
|
|
|
+ bpf_printk("go_update_header: Using old hmap implementation");
|
|
|
|
|
+
|
|
|
char key[CW_HEADER_KEY_LENGTH] = CW_HEADER_KEY_VAL;
|
|
char key[CW_HEADER_KEY_LENGTH] = CW_HEADER_KEY_VAL;
|
|
|
- void *ptr = cw_write_target_data(key, CW_HEADER_KEY_LENGTH,proc_info);
|
|
|
|
|
|
|
+ void *ptr = cw_write_target_data(key, CW_HEADER_KEY_LENGTH, proc_info);
|
|
|
if (ptr == NULL) {
|
|
if (ptr == NULL) {
|
|
|
-// cw_bpf_debug("inject_header: Failed to write key to user");
|
|
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to write key");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
-// bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};
|
|
|
|
|
|
|
|
|
|
- // 往前提
|
|
|
|
|
-// char val[CW_HEADER_VAL_LENGTH];
|
|
|
|
|
-// bpf_probe_read(val, sizeof(val),&header_str);
|
|
|
|
|
- void * header_str_ptr = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH,proc_info);
|
|
|
|
|
|
|
+ void * header_str_ptr = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH, proc_info);
|
|
|
if(header_str_ptr == NULL) {
|
|
if(header_str_ptr == NULL) {
|
|
|
-// cw_bpf_debug("inject_header: Failed to write value to user");
|
|
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to write header_str");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// if (bucket_index < 0 || bucket_index >= 8){
|
|
|
|
|
-// return -1;
|
|
|
|
|
-// }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
// The go string pointing to the above val
|
|
// The go string pointing to the above val
|
|
|
struct go_string_ot header_value = {.len = CW_HEADER_VAL_LENGTH, .str = header_str_ptr};
|
|
struct go_string_ot header_value = {.len = CW_HEADER_VAL_LENGTH, .str = header_str_ptr};
|
|
|
- void * header_value_ptr = cw_write_target_data((void*)&header_value, sizeof(header_value),proc_info);
|
|
|
|
|
|
|
+ void * header_value_ptr = cw_write_target_data((void*)&header_value, sizeof(header_value), proc_info);
|
|
|
if(header_value_ptr == NULL) {
|
|
if(header_value_ptr == NULL) {
|
|
|
- cw_bpf_debug("inject_header: Failed to write go_string to user");
|
|
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to write go_string");
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
char traceparent_tophash = 0xee;
|
|
char traceparent_tophash = 0xee;
|
|
|
- u8 bucket_index = curr_keyvalue_count & 0x7;
|
|
|
|
|
- bucket_map_value->tophash[bucket_index] = traceparent_tophash;
|
|
|
|
|
- bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};
|
|
|
|
|
- bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = header_value_ptr, .cap = 1, .len = 1};
|
|
|
|
|
-
|
|
|
|
|
- // Last, go_slice pointing to the above go_string
|
|
|
|
|
-// return 1;
|
|
|
|
|
-// bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};
|
|
|
|
|
|
|
+ u8 idx = curr_keyvalue_count & 0x7; // Use calculated index
|
|
|
|
|
+ bucket_map_value->tophash[idx] = traceparent_tophash;
|
|
|
|
|
+ bucket_map_value->keys[idx] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};
|
|
|
|
|
+ bucket_map_value->values[idx] = (struct go_slice_ot) {.array = header_value_ptr, .cap = 1, .len = 1};
|
|
|
|
|
|
|
|
// Update the map header count field
|
|
// Update the map header count field
|
|
|
curr_keyvalue_count = curr_keyvalue_count + 1;
|
|
curr_keyvalue_count = curr_keyvalue_count + 1;
|
|
|
long res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
|
|
long res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
|
|
|
if (res < 0) {
|
|
if (res < 0) {
|
|
|
- cw_bpf_debug("Failed to update key-value count in map header");
|
|
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to update count, res=%ld", res);
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Update the bucket
|
|
// Update the bucket
|
|
|
res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
|
|
res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
|
|
|
if (res < 0) {
|
|
if (res < 0) {
|
|
|
- cw_bpf_debug("Failed to update bucket content");
|
|
|
|
|
|
|
+ bpf_printk("go_update_header: Failed to update bucket, res=%ld", res);
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
|
|
bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
|
|
|
|
|
+ bpf_printk("go_update_header: SUCCESS - old hmap injection completed");
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|