You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by li...@apache.org on 2023/02/24 01:58:59 UTC
[skywalking-rover] branch main updated: Support monitoring TLS-based network data in continuous profiling (#79)
This is an automated email from the ASF dual-hosted git repository.
liuhan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-rover.git
The following commit(s) were added to refs/heads/main by this push:
new 8252217 Support monitoring TLS-based network data in continuous profiling (#79)
8252217 is described below
commit 8252217ce94bf2f8cdc00fd7f708f04ae344449e
Author: mrproliu <74...@qq.com>
AuthorDate: Fri Feb 24 09:58:53 2023 +0800
Support monitoring TLS-based network data in continuous profiling (#79)
---
bpf/include/goid.c | 70 +++
.../network/go_tls.h => include/symbol_offsets.h} | 146 +++--
bpf/profiling/{network => continuous}/go_tls.c | 106 ++--
.../{network/openssl.h => continuous/go_tls.h} | 25 +-
bpf/profiling/continuous/network.c | 32 +-
bpf/profiling/continuous/network.h | 2 +-
bpf/profiling/continuous/openssl.c | 106 ++++
bpf/profiling/{network => continuous}/openssl.h | 20 +-
bpf/profiling/network/go_tls.c | 46 +-
bpf/profiling/network/go_tls.h | 104 +---
bpf/profiling/network/netmonitor.c | 4 -
bpf/profiling/network/openssl.c | 3 +-
bpf/profiling/network/openssl.h | 18 -
pkg/process/finders/base/tool.go | 4 +-
.../continuous/checker/bpf/network/http1.go | 2 +-
.../continuous/checker/bpf/network/network.go | 55 +-
.../continuous/checker/bpf/network/process.go | 82 +++
.../continuous/checker/bpf/network/reader.go | 2 +-
.../continuous/checker/bpf/network/ssl.go | 37 +-
pkg/profiling/task/network/analyze/base/enums.go | 7 -
pkg/profiling/task/network/ssl.go | 595 +--------------------
pkg/profiling/task/offcpu/runner.go | 10 +-
pkg/profiling/task/oncpu/runner.go | 10 +-
pkg/tools/btf/linker.go | 4 +-
pkg/tools/{ => process}/process.go | 10 +-
pkg/tools/ssl/envoy.go | 75 +++
pkg/tools/ssl/gotls.go | 258 +++++++++
pkg/tools/ssl/node.go | 211 ++++++++
pkg/tools/ssl/openssl.go | 141 +++++
.../ssl_test.go => tools/ssl/openssl_test.go} | 19 +-
pkg/tools/ssl/ssl.go | 146 +++++
31 files changed, 1335 insertions(+), 1015 deletions(-)
diff --git a/bpf/include/goid.c b/bpf/include/goid.c
new file mode 100644
index 0000000..80c0813
--- /dev/null
+++ b/bpf/include/goid.c
@@ -0,0 +1,70 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "symbol_offsets.h"
+
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 1024);
+ __type(key, __u64);
+ __type(value, __u64);
+} go_tgid_goid_map SEC(".maps");
+static __inline __u64 get_goid(__u64 id) {
+ __u64 *val;
+ val = bpf_map_lookup_elem(&go_tgid_goid_map, &id);
+ return !val ? 0 : *val;
+}
+static __inline void set_goid(__u64 id, __u64 goid) {
+ bpf_map_update_elem(&go_tgid_goid_map, &id, &goid, 0);
+}
+
+SEC("uprobe/casgstatus")
+int go_casgstatus(struct pt_regs* ctx) {
+ const void* sp = (const void*)PT_REGS_SP(ctx);
+ __u64* regs = go_regabi_regs(ctx);
+ if (regs == NULL) {
+ return 0;
+ }
+
+ __u64 id = bpf_get_current_pid_tgid();
+ __u32 tgid = id >> 32;
+ struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
+ if (symaddrs == NULL) {
+ return 0;
+ }
+
+ // get runtime.g
+ void* gptr = NULL;
+ assign_go_tls_arg(&gptr, sizeof(gptr), symaddrs->casg_status_gp_loc, sp, regs);
+ if (gptr == NULL) {
+ return 0;
+ }
+
+ // get goid in runtime.g
+ int64_t goid;
+ bpf_probe_read(&goid, sizeof(goid), gptr + symaddrs->gid_offset);
+
+ // newval in runtime.g
+ __u32 status;
+ assign_go_tls_arg(&status, sizeof(status), symaddrs->casg_status_new_val_loc, sp, regs);
+
+ // check the status is running
+ if (status == 2) {
+ set_goid(id, goid);
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/bpf/profiling/network/go_tls.h b/bpf/include/symbol_offsets.h
similarity index 66%
copy from bpf/profiling/network/go_tls.h
copy to bpf/include/symbol_offsets.h
index 1428a4e..33b19ef 100644
--- a/bpf/profiling/network/go_tls.h
+++ b/bpf/include/symbol_offsets.h
@@ -15,61 +15,36 @@
// specific language governing permissions and limitations
// under the License.
-struct go_tls_arg_location_t {
- __u32 type;
- __u32 offset;
-};
-
-struct go_tls_args_symaddr_t {
- __u64 fd_sys_offset;
- __u64 tls_conn_offset;
- __u64 gid_offset;
- __u64 tcp_conn_offset;
-
- // casg
- struct go_tls_arg_location_t casg_status_gp_loc;
- struct go_tls_arg_location_t casg_status_new_val_loc;
-
- // read
- struct go_tls_arg_location_t read_connection_loc;
- struct go_tls_arg_location_t read_buffer_loc;
- struct go_tls_arg_location_t read_ret0_loc;
- struct go_tls_arg_location_t read_ret1_loc;
-
- // write
- struct go_tls_arg_location_t write_connection_loc;
- struct go_tls_arg_location_t write_buffer_loc;
- struct go_tls_arg_location_t write_ret0_loc;
- struct go_tls_arg_location_t write_ret1_loc;
+#pragma once
+
+// ------------------------------------------ openssl start -------------------------------------------------------
+struct openssl_symaddr {
+ // read the BIO offset from ssl
+ __u32 bio_read_offset;
+ __u32 bio_write_offset;
+ // read the fd offset from BIO
+ __u32 fd_offset;
+ // read the SSL is server side or not
+ __u32 server_offset;
};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 10000);
__type(key, __u32);
- __type(value, struct go_tls_args_symaddr_t);
-} go_tls_args_symaddr_map SEC(".maps");
-static __always_inline struct go_tls_args_symaddr_t* get_go_tls_args_symaddr(__u32 tgid) {
- struct go_tls_args_symaddr_t *addr = bpf_map_lookup_elem(&go_tls_args_symaddr_map, &tgid);
+ __type(value, struct openssl_symaddr);
+} openssl_symaddr_map SEC(".maps");
+static __inline struct openssl_symaddr* get_openssl_symaddr(__u32 tgid) {
+ struct openssl_symaddr *addr = bpf_map_lookup_elem(&openssl_symaddr_map, &tgid);
return addr;
}
+// ------------------------------------------ openssl end -------------------------------------------------------
-struct go_tls_tgid_goid_t {
- __u64 tgid;
- __u64 goid;
-};
-struct go_tls_connection_args_t {
- void* connection_ptr;
- char* buffer_ptr;
- __u64 start_nacs;
+// ------------------------------------------ go tls start -------------------------------------------------------
+struct go_tls_arg_location_t {
+ __u32 type;
+ __u32 offset;
};
-struct {
- __uint(type, BPF_MAP_TYPE_HASH);
- __uint(max_entries, 10000);
- __type(key, struct go_tls_tgid_goid_t);
- __type(value, struct go_tls_connection_args_t);
-} go_tls_active_connection_args SEC(".maps");
-
struct go_regabi_regs_t {
__u64 regs[9];
@@ -82,7 +57,7 @@ struct {
} go_regabi_regs_map SEC(".maps");
// Copies the registers of the golang ABI, so that they can be
// easily accessed using an offset.
-static __always_inline uint64_t* go_regabi_regs(const struct pt_regs* ctx) {
+static __always_inline __u64* go_regabi_regs(const struct pt_regs* ctx) {
__u32 zero = 0;
struct go_regabi_regs_t* regs_heap_var = bpf_map_lookup_elem(&go_regabi_regs_map, &zero);
if (regs_heap_var == NULL) {
@@ -102,13 +77,43 @@ static __always_inline uint64_t* go_regabi_regs(const struct pt_regs* ctx) {
return regs_heap_var->regs;
}
-struct go_interface {
- int64_t type;
- void* ptr;
+struct go_tls_args_symaddr_t {
+ __u64 fd_sys_offset;
+ __u64 tls_conn_offset;
+ __u64 gid_offset;
+ __u64 tcp_conn_offset;
+ __u64 is_client_offset;
+
+ // casg
+ struct go_tls_arg_location_t casg_status_gp_loc;
+ struct go_tls_arg_location_t casg_status_new_val_loc;
+
+ // read
+ struct go_tls_arg_location_t read_connection_loc;
+ struct go_tls_arg_location_t read_buffer_loc;
+ struct go_tls_arg_location_t read_ret0_loc;
+ struct go_tls_arg_location_t read_ret1_loc;
+
+ // write
+ struct go_tls_arg_location_t write_connection_loc;
+ struct go_tls_arg_location_t write_buffer_loc;
+ struct go_tls_arg_location_t write_ret0_loc;
+ struct go_tls_arg_location_t write_ret1_loc;
};
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u32);
+ __type(value, struct go_tls_args_symaddr_t);
+} go_tls_args_symaddr_map SEC(".maps");
+static __always_inline struct go_tls_args_symaddr_t* get_go_tls_args_symaddr(__u32 tgid) {
+ struct go_tls_args_symaddr_t *addr = bpf_map_lookup_elem(&go_tls_args_symaddr_map, &tgid);
+ return addr;
+}
+
static __always_inline void assign_go_tls_arg(void* arg, size_t arg_size, struct go_tls_arg_location_t loc, const void* sp,
- uint64_t* regs) {
+ __u64* regs) {
// stack type
if (loc.type == 1) {
bpf_probe_read(arg, arg_size, sp + loc.offset);
@@ -120,32 +125,25 @@ static __always_inline void assign_go_tls_arg(void* arg, size_t arg_size, struct
}
}
-static __always_inline int get_fd_from_go_tls_conn(struct go_interface conn, struct go_tls_args_symaddr_t* symaddr) {
- // read connection
- bpf_probe_read(&conn, sizeof(conn), conn.ptr + symaddr->tls_conn_offset);
-
- if (conn.type != symaddr->tcp_conn_offset) {
- return 0;
- }
+struct go_interface {
+ int64_t type;
+ void* ptr;
+};
+// ------------------------------------------ go tls end -------------------------------------------------------
- void* fd_ptr;
- bpf_probe_read(&fd_ptr, sizeof(fd_ptr), conn.ptr);
- __u64 sysfd;
- bpf_probe_read(&sysfd, sizeof(sysfd), fd_ptr + symaddr->fd_sys_offset);
- return sysfd;
-}
+// ------------------------------------------ envoy tls start -------------------------------------------------------
+struct envoy_tls_args_symaddr_t {
+ __u64 is_server_offset;
+};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
- __uint(max_entries, 1024);
- __type(key, __u64);
- __type(value, __u64);
-} go_tgid_goid_map SEC(".maps");
-static __inline __u64 get_goid(__u64 tgid) {
- __u64 *val;
- val = bpf_map_lookup_elem(&go_tgid_goid_map, &tgid);
- return !val ? 0 : *val;
+ __uint(max_entries, 10000);
+ __type(key, __u32);
+ __type(value, struct envoy_tls_args_symaddr_t);
+} envoy_tls_args_symaddr_map SEC(".maps");
+static __always_inline struct envoy_tls_args_symaddr_t* get_envoy_tls_args_symaddr(__u32 tgid) {
+ struct envoy_tls_args_symaddr_t *addr = bpf_map_lookup_elem(&envoy_tls_args_symaddr_map, &tgid);
+ return addr;
}
-static __inline void set_goid(__u64 tgid, __u64 goid) {
- bpf_map_update_elem(&go_tgid_goid_map, &tgid, &goid, 0);
-}
\ No newline at end of file
+// ------------------------------------------ envoy tls end -------------------------------------------------------
\ No newline at end of file
diff --git a/bpf/profiling/network/go_tls.c b/bpf/profiling/continuous/go_tls.c
similarity index 67%
copy from bpf/profiling/network/go_tls.c
copy to bpf/profiling/continuous/go_tls.c
index d7af96b..60ed538 100644
--- a/bpf/profiling/network/go_tls.c
+++ b/bpf/profiling/continuous/go_tls.c
@@ -16,49 +16,17 @@
// under the License.
#include "go_tls.h"
+#include "goid.c"
-SEC("uprobe/casgstatus")
-int go_casgstatus(struct pt_regs* ctx) {
- const void* sp = (const void*)PT_REGS_SP(ctx);
- uint64_t* regs = go_regabi_regs(ctx);
- if (regs == NULL) {
- return 0;
- }
-
+SEC("uprobe/go_tls_write")
+int go_tls_write(struct pt_regs* ctx) {
__u64 id = bpf_get_current_pid_tgid();
__u32 tgid = id >> 32;
- struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
- if (symaddrs == NULL) {
- return 0;
- }
- // get runtime.g
- void* gptr = NULL;
- assign_go_tls_arg(&gptr, sizeof(gptr), symaddrs->casg_status_gp_loc, sp, regs);
- if (gptr == NULL) {
+ if (tgid_should_trace(tgid) == false) {
return 0;
}
- // get goid in runtime.g
- int64_t goid;
- bpf_probe_read(&goid, sizeof(goid), gptr + symaddrs->gid_offset);
-
- // newval in runtime.g
- __u32 status;
- assign_go_tls_arg(&status, sizeof(status), symaddrs->casg_status_new_val_loc, sp, regs);
-
- // check the status is running
- if (status == 2) {
- set_goid(id, goid);
- }
- return 0;
-}
-
-SEC("uprobe/go_tls_write")
-int go_tls_write(struct pt_regs* ctx) {
- __u64 id = bpf_get_current_pid_tgid();
- __u32 tgid = id >> 32;
-
__u64 goid = get_goid(id);
if (goid == 0) {
return 0;
@@ -70,17 +38,24 @@ int go_tls_write(struct pt_regs* ctx) {
}
const void* sp = (const void*)PT_REGS_SP(ctx);
- uint64_t* regs = go_regabi_regs(ctx);
+ __u64* regs = go_regabi_regs(ctx);
if (regs == NULL) {
return 0;
}
+ // ignore if the connection is client side
+ struct go_tls_connection_args_t data_args = {};
+ assign_go_tls_arg(&data_args.connection_ptr, sizeof(data_args.connection_ptr), symaddrs->write_connection_loc, sp, regs);
+ __u8 is_client;
+ bpf_probe_read(&is_client, sizeof(is_client), data_args.connection_ptr + symaddrs->is_client_offset);
+ if (is_client == 1) {
+ return 0;
+ }
+
struct go_tls_tgid_goid_t tgid_goid = {};
tgid_goid.tgid = tgid;
tgid_goid.goid = goid;
- struct go_tls_connection_args_t data_args = {};
- assign_go_tls_arg(&data_args.connection_ptr, sizeof(data_args.connection_ptr), symaddrs->write_connection_loc, sp, regs);
assign_go_tls_arg(&data_args.buffer_ptr, sizeof(data_args.buffer_ptr), symaddrs->write_buffer_loc, sp, regs);
data_args.start_nacs = bpf_ktime_get_ns();
bpf_map_update_elem(&go_tls_active_connection_args, &tgid_goid, &data_args, 0);
@@ -103,7 +78,7 @@ int go_tls_write_ret(struct pt_regs* ctx) {
}
const void* sp = (const void*)PT_REGS_SP(ctx);
- uint64_t* regs = go_regabi_regs(ctx);
+ __u64* regs = go_regabi_regs(ctx);
if (regs == NULL) {
return 0;
}
@@ -122,22 +97,10 @@ int go_tls_write_ret(struct pt_regs* ctx) {
struct go_tls_connection_args_t *args = bpf_map_lookup_elem(&go_tls_active_connection_args, &tgid_goid);
if (args) {
- struct go_interface conn_intf = {};
- conn_intf.type = 1;
- conn_intf.ptr = args->connection_ptr;
- int fd = get_fd_from_go_tls_conn(conn_intf, symaddrs);
-
- set_conn_as_ssl(ctx, tgid, fd, SOCKET_OPTS_TYPE_GOTLS_WRITE);
-
- struct sock_data_args_t data_args = {};
- data_args.fd = fd;
- data_args.buf = args->buffer_ptr;
- data_args.start_nacs = args->start_nacs;
- data_args.data_id = ssl_get_data_id(6, id, fd);
-
- process_write_data(ctx, id, &data_args, retval0, SOCK_DATA_DIRECTION_EGRESS, false, SOCKET_OPTS_TYPE_GOTLS_WRITE, true);
+ process_data(ctx, id, args->connection_ptr, args->buffer_ptr, retval0, args->start_nacs);
}
bpf_map_delete_elem(&go_tls_active_connection_args, &tgid_goid);
+
return 0;
}
@@ -146,6 +109,10 @@ int go_tls_read(struct pt_regs* ctx) {
__u64 id = bpf_get_current_pid_tgid();
__u32 tgid = id >> 32;
+ if (tgid_should_trace(tgid) == false) {
+ return 0;
+ }
+
__u64 goid = get_goid(id);
if (goid == 0) {
return 0;
@@ -157,19 +124,25 @@ int go_tls_read(struct pt_regs* ctx) {
}
const void* sp = (const void*)PT_REGS_SP(ctx);
- uint64_t* regs = go_regabi_regs(ctx);
+ __u64* regs = go_regabi_regs(ctx);
if (regs == NULL) {
return 0;
}
+ // ignore if the connection is client side
+ struct go_tls_connection_args_t data_args = {};
+ assign_go_tls_arg(&data_args.connection_ptr, sizeof(data_args.connection_ptr), symaddrs->write_connection_loc, sp, regs);
+ __u8 is_client;
+ bpf_probe_read(&is_client, sizeof(is_client), data_args.connection_ptr + symaddrs->is_client_offset);
+ if (is_client == 1) {
+ return 0;
+ }
+
struct go_tls_tgid_goid_t tgid_goid = {};
tgid_goid.tgid = tgid;
tgid_goid.goid = goid;
- struct go_tls_connection_args_t data_args = {};
- assign_go_tls_arg(&data_args.connection_ptr, sizeof(data_args.connection_ptr), symaddrs->read_connection_loc, sp, regs);
assign_go_tls_arg(&data_args.buffer_ptr, sizeof(data_args.buffer_ptr), symaddrs->read_buffer_loc, sp, regs);
- data_args.start_nacs = bpf_ktime_get_ns();
bpf_map_update_elem(&go_tls_active_connection_args, &tgid_goid, &data_args, 0);
return 0;
}
@@ -190,7 +163,7 @@ int go_tls_read_ret(struct pt_regs* ctx) {
}
const void* sp = (const void*)PT_REGS_SP(ctx);
- uint64_t* regs = go_regabi_regs(ctx);
+ __u64* regs = go_regabi_regs(ctx);
if (regs == NULL) {
return 0;
}
@@ -209,20 +182,7 @@ int go_tls_read_ret(struct pt_regs* ctx) {
struct go_tls_connection_args_t *args = bpf_map_lookup_elem(&go_tls_active_connection_args, &tgid_goid);
if (args) {
- struct go_interface conn_intf = {};
- conn_intf.type = 1;
- conn_intf.ptr = args->connection_ptr;
- int fd = get_fd_from_go_tls_conn(conn_intf, symaddrs);
-
- set_conn_as_ssl(ctx, tgid, fd, SOCKET_OPTS_TYPE_GOTLS_READ);
-
- struct sock_data_args_t data_args = {};
- data_args.fd = fd;
- data_args.buf = args->buffer_ptr;
- data_args.start_nacs = args->start_nacs;
- data_args.data_id = ssl_get_data_id(8, id, fd);
-
- process_write_data(ctx, id, &data_args, retval0, SOCK_DATA_DIRECTION_INGRESS, false, SOCKET_OPTS_TYPE_GOTLS_WRITE, true);
+ process_data(ctx, id, args->connection_ptr, args->buffer_ptr, retval0, bpf_ktime_get_ns());
}
bpf_map_delete_elem(&go_tls_active_connection_args, &tgid_goid);
return 0;
diff --git a/bpf/profiling/network/openssl.h b/bpf/profiling/continuous/go_tls.h
similarity index 65%
copy from bpf/profiling/network/openssl.h
copy to bpf/profiling/continuous/go_tls.h
index 61e8425..43d3bff 100644
--- a/bpf/profiling/network/openssl.h
+++ b/bpf/profiling/continuous/go_tls.h
@@ -15,21 +15,18 @@
// specific language governing permissions and limitations
// under the License.
-struct openssl_fd_symaddr {
- // read the BIO offset from ssl
- __u32 bio_read_offset;
- __u32 bio_write_offset;
- // read the fd offset from BIO
- __u32 fd_offset;
+struct go_tls_tgid_goid_t {
+ __u64 tgid;
+ __u64 goid;
+};
+struct go_tls_connection_args_t {
+ void* connection_ptr;
+ char* buffer_ptr;
+ __u64 start_nacs;
};
-
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 10000);
- __type(key, __u32);
- __type(value, struct openssl_fd_symaddr);
-} openssl_fd_symaddr_finder SEC(".maps");
-static __inline struct openssl_fd_symaddr* get_openssl_fd_symaddr(__u32 tgid) {
- struct openssl_fd_symaddr *addr = bpf_map_lookup_elem(&openssl_fd_symaddr_finder, &tgid);
- return addr;
-}
+ __type(key, struct go_tls_tgid_goid_t);
+ __type(value, struct go_tls_connection_args_t);
+} go_tls_active_connection_args SEC(".maps");
\ No newline at end of file
diff --git a/bpf/profiling/continuous/network.c b/bpf/profiling/continuous/network.c
index cd0a603..c37bdfc 100644
--- a/bpf/profiling/continuous/network.c
+++ b/bpf/profiling/continuous/network.c
@@ -53,13 +53,7 @@ static __always_inline bool socket_should_trace(__u64 id, struct sock *sock) {
return true;
}
-static __always_inline void process_data(struct pt_regs *ctx, __u64 id, void *channel_ref, struct msghdr *msg) {
- const struct iovec *iovec;
- iovec = _KERNEL(msg->msg_iter.iov);
- struct iovec iov;
- bpf_probe_read(&iov, sizeof(iov), iovec);
- char* buf = (char *)iov.iov_base;
- __u64 size = iov.iov_len;
+static __always_inline void process_data(struct pt_regs *ctx, __u64 id, void *channel_ref, char *buf, __u64 size, __u64 timestamp) {
if (size <= 0) {
return;
}
@@ -72,12 +66,12 @@ static __always_inline void process_data(struct pt_regs *ctx, __u64 id, void *ch
if (reader == NULL) {
return;
}
- asm volatile("%[size] &= 0x9f;\n" ::[size] "+r"(size) :);
+ asm volatile("%[size] &= 0xff;\n" ::[size] "+r"(size) :);
bpf_probe_read(&reader->buffer, size & MAX_PROTOCOL_SOCKET_READ_LENGTH, buf);
__u8 protocol;
__u32 direction = analyze_protocol(reader->buffer, size & MAX_PROTOCOL_SOCKET_READ_LENGTH, &protocol);
if (protocol != CONNECTION_PROTOCOL_UNKNOWN) {
- reader->timestamp = bpf_ktime_get_ns();
+ reader->timestamp = timestamp;
reader->channel_ref = channel_ref;
reader->pid = (__u32)(id >> 32);
reader->protocol = protocol;
@@ -87,6 +81,17 @@ static __always_inline void process_data(struct pt_regs *ctx, __u64 id, void *ch
}
}
+static __always_inline void process_msghdr_data(struct pt_regs *ctx, __u64 id, void *channel_ref, struct msghdr *msg) {
+ const struct iovec *iovec;
+ iovec = _KERNEL(msg->msg_iter.iov);
+ struct iovec iov;
+ bpf_probe_read(&iov, sizeof(iov), iovec);
+ char* buf = (char *)iov.iov_base;
+ __u64 size = iov.iov_len;
+
+ return process_data(ctx, id, channel_ref, buf, size, bpf_ktime_get_ns());
+}
+
SEC("kprobe/tcp_sendmsg")
int tcp_sendmsg(struct pt_regs *ctx) {
__u64 id = bpf_get_current_pid_tgid();
@@ -96,7 +101,7 @@ int tcp_sendmsg(struct pt_regs *ctx) {
}
struct msghdr *msg = (void *)PT_REGS_PARM2(ctx);
- process_data(ctx, id, s, msg);
+ process_msghdr_data(ctx, id, s, msg);
return 0;
}
@@ -122,8 +127,11 @@ int ret_tcp_recvmsg(struct pt_regs *ctx) {
struct recv_msg_args *args = bpf_map_lookup_elem(&receiving_args, &id);
int bytes_count = PT_REGS_RC(ctx);
if (args != NULL && bytes_count > 0) {
- process_data(ctx, id, args->sock, args->msg);
+ process_msghdr_data(ctx, id, args->sock, args->msg);
}
bpf_map_delete_elem(&receiving_args, &id);
return 0;
-}
\ No newline at end of file
+}
+
+#include "openssl.c"
+#include "go_tls.c"
diff --git a/bpf/profiling/continuous/network.h b/bpf/profiling/continuous/network.h
index b8c4dd3..461b037 100644
--- a/bpf/profiling/continuous/network.h
+++ b/bpf/profiling/continuous/network.h
@@ -18,7 +18,7 @@
#include "api.h"
#include "skb.h"
-#define MAX_PROTOCOL_SOCKET_READ_LENGTH 158
+#define MAX_PROTOCOL_SOCKET_READ_LENGTH 255
struct {
__uint(type, BPF_MAP_TYPE_HASH);
diff --git a/bpf/profiling/continuous/openssl.c b/bpf/profiling/continuous/openssl.c
new file mode 100644
index 0000000..fe24eef
--- /dev/null
+++ b/bpf/profiling/continuous/openssl.c
@@ -0,0 +1,106 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "symbol_offsets.h"
+#include "openssl.h"
+
+static __always_inline bool openssl_should_trace(__u64 id, void *ssl) {
+ // check the pid is monitoring
+ __u32 tgid = (__u32)(id >> 32);
+ if (tgid_should_trace(tgid) == false) {
+ return false;
+ }
+
+ // check the socket if server side
+ struct openssl_symaddr* addr = get_openssl_symaddr(tgid);
+ if (addr != NULL) {
+ int is_server;
+ bpf_probe_read(&is_server, sizeof(is_server), ssl + addr->server_offset);
+ if (is_server == 1) {
+ return true;
+ }
+ return false;
+ }
+ struct envoy_tls_args_symaddr_t *envoy_addr = get_envoy_tls_args_symaddr(tgid);
+ if (envoy_addr != NULL) {
+ __u8 is_server_from_nginx;
+ bpf_probe_read(&is_server_from_nginx, sizeof(is_server_from_nginx), ssl + envoy_addr->is_server_offset);
+ if (is_server_from_nginx == 1) {
+ return true;
+ }
+ return false;
+ }
+
+ // could not check is server or client, just ignore it
+ return false;
+}
+
+SEC("uprobe/ssl_write")
+int openssl_write(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ void* ssl = (void*)PT_REGS_PARM1(ctx);
+ if (openssl_should_trace(id, ssl) == false) {
+ return 0;
+ }
+ char* buf = (char*)PT_REGS_PARM2(ctx);
+
+ struct openssl_args args = {};
+ args.ssl = ssl;
+ args.buf = buf;
+ args.timestamp = bpf_ktime_get_ns();
+ bpf_map_update_elem(&openssl_args_map, &id, &args, 0);
+ return 0;
+}
+
+SEC("uretprobe/ssl_write")
+int openssl_write_ret(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct openssl_args *args = bpf_map_lookup_elem(&openssl_args_map, &id);
+ int bytes_count = PT_REGS_RC(ctx);
+ if (args && bytes_count > 0) {
+ process_data(ctx, id, args->ssl, args->buf, bytes_count, args->timestamp);
+ }
+ bpf_map_delete_elem(&openssl_args_map, &id);
+ return 0;
+}
+
+SEC("uprobe/ssl_read")
+int openssl_read(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ void* ssl = (void*)PT_REGS_PARM1(ctx);
+ if (openssl_should_trace(id, ssl) == false) {
+ return 0;
+ }
+ char* buf = (char*)PT_REGS_PARM2(ctx);
+ struct openssl_args args = {};
+ args.ssl = ssl;
+ args.buf = buf;
+ bpf_map_update_elem(&openssl_args_map, &id, &args, 0);
+ return 0;
+}
+
+SEC("uretprobe/ssl_read")
+int openssl_read_ret(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct openssl_args *args = bpf_map_lookup_elem(&openssl_args_map, &id);
+ int bytes_count = PT_REGS_RC(ctx);
+ if (args && bytes_count > 0) {
+ process_data(ctx, id, args->ssl, args->buf, bytes_count, bpf_ktime_get_ns());
+ }
+ bpf_map_delete_elem(&openssl_args_map, &id);
+ return 0;
+}
\ No newline at end of file
diff --git a/bpf/profiling/network/openssl.h b/bpf/profiling/continuous/openssl.h
similarity index 65%
copy from bpf/profiling/network/openssl.h
copy to bpf/profiling/continuous/openssl.h
index 61e8425..ee0ef84 100644
--- a/bpf/profiling/network/openssl.h
+++ b/bpf/profiling/continuous/openssl.h
@@ -15,21 +15,15 @@
// specific language governing permissions and limitations
// under the License.
-struct openssl_fd_symaddr {
- // read the BIO offset from ssl
- __u32 bio_read_offset;
- __u32 bio_write_offset;
- // read the fd offset from BIO
- __u32 fd_offset;
+struct openssl_args {
+ void* ssl;
+ char* buf;
+ __u64 timestamp;
};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 10000);
- __type(key, __u32);
- __type(value, struct openssl_fd_symaddr);
-} openssl_fd_symaddr_finder SEC(".maps");
-static __inline struct openssl_fd_symaddr* get_openssl_fd_symaddr(__u32 tgid) {
- struct openssl_fd_symaddr *addr = bpf_map_lookup_elem(&openssl_fd_symaddr_finder, &tgid);
- return addr;
-}
+ __type(key, __u64);
+ __type(value, struct openssl_args);
+} openssl_args_map SEC(".maps");
diff --git a/bpf/profiling/network/go_tls.c b/bpf/profiling/network/go_tls.c
index d7af96b..3fde4a5 100644
--- a/bpf/profiling/network/go_tls.c
+++ b/bpf/profiling/network/go_tls.c
@@ -16,43 +16,7 @@
// under the License.
#include "go_tls.h"
-
-SEC("uprobe/casgstatus")
-int go_casgstatus(struct pt_regs* ctx) {
- const void* sp = (const void*)PT_REGS_SP(ctx);
- uint64_t* regs = go_regabi_regs(ctx);
- if (regs == NULL) {
- return 0;
- }
-
- __u64 id = bpf_get_current_pid_tgid();
- __u32 tgid = id >> 32;
- struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
- if (symaddrs == NULL) {
- return 0;
- }
-
- // get runtime.g
- void* gptr = NULL;
- assign_go_tls_arg(&gptr, sizeof(gptr), symaddrs->casg_status_gp_loc, sp, regs);
- if (gptr == NULL) {
- return 0;
- }
-
- // get goid in runtime.g
- int64_t goid;
- bpf_probe_read(&goid, sizeof(goid), gptr + symaddrs->gid_offset);
-
- // newval in runtime.g
- __u32 status;
- assign_go_tls_arg(&status, sizeof(status), symaddrs->casg_status_new_val_loc, sp, regs);
-
- // check the status is running
- if (status == 2) {
- set_goid(id, goid);
- }
- return 0;
-}
+#include "goid.c"
SEC("uprobe/go_tls_write")
int go_tls_write(struct pt_regs* ctx) {
@@ -70,7 +34,7 @@ int go_tls_write(struct pt_regs* ctx) {
}
const void* sp = (const void*)PT_REGS_SP(ctx);
- uint64_t* regs = go_regabi_regs(ctx);
+ __u64* regs = go_regabi_regs(ctx);
if (regs == NULL) {
return 0;
}
@@ -103,7 +67,7 @@ int go_tls_write_ret(struct pt_regs* ctx) {
}
const void* sp = (const void*)PT_REGS_SP(ctx);
- uint64_t* regs = go_regabi_regs(ctx);
+ __u64* regs = go_regabi_regs(ctx);
if (regs == NULL) {
return 0;
}
@@ -157,7 +121,7 @@ int go_tls_read(struct pt_regs* ctx) {
}
const void* sp = (const void*)PT_REGS_SP(ctx);
- uint64_t* regs = go_regabi_regs(ctx);
+ __u64* regs = go_regabi_regs(ctx);
if (regs == NULL) {
return 0;
}
@@ -190,7 +154,7 @@ int go_tls_read_ret(struct pt_regs* ctx) {
}
const void* sp = (const void*)PT_REGS_SP(ctx);
- uint64_t* regs = go_regabi_regs(ctx);
+ __u64* regs = go_regabi_regs(ctx);
if (regs == NULL) {
return 0;
}
diff --git a/bpf/profiling/network/go_tls.h b/bpf/profiling/network/go_tls.h
index 1428a4e..1057ef9 100644
--- a/bpf/profiling/network/go_tls.h
+++ b/bpf/profiling/network/go_tls.h
@@ -15,44 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-struct go_tls_arg_location_t {
- __u32 type;
- __u32 offset;
-};
-
-struct go_tls_args_symaddr_t {
- __u64 fd_sys_offset;
- __u64 tls_conn_offset;
- __u64 gid_offset;
- __u64 tcp_conn_offset;
-
- // casg
- struct go_tls_arg_location_t casg_status_gp_loc;
- struct go_tls_arg_location_t casg_status_new_val_loc;
-
- // read
- struct go_tls_arg_location_t read_connection_loc;
- struct go_tls_arg_location_t read_buffer_loc;
- struct go_tls_arg_location_t read_ret0_loc;
- struct go_tls_arg_location_t read_ret1_loc;
-
- // write
- struct go_tls_arg_location_t write_connection_loc;
- struct go_tls_arg_location_t write_buffer_loc;
- struct go_tls_arg_location_t write_ret0_loc;
- struct go_tls_arg_location_t write_ret1_loc;
-};
-
-struct {
- __uint(type, BPF_MAP_TYPE_HASH);
- __uint(max_entries, 10000);
- __type(key, __u32);
- __type(value, struct go_tls_args_symaddr_t);
-} go_tls_args_symaddr_map SEC(".maps");
-static __always_inline struct go_tls_args_symaddr_t* get_go_tls_args_symaddr(__u32 tgid) {
- struct go_tls_args_symaddr_t *addr = bpf_map_lookup_elem(&go_tls_args_symaddr_map, &tgid);
- return addr;
-}
+#include "symbol_offsets.h"
struct go_tls_tgid_goid_t {
__u64 tgid;
@@ -70,56 +33,6 @@ struct {
__type(value, struct go_tls_connection_args_t);
} go_tls_active_connection_args SEC(".maps");
-
-struct go_regabi_regs_t {
- __u64 regs[9];
-};
-struct {
- __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
- __type(key, __u32);
- __type(value, struct go_regabi_regs_t);
- __uint(max_entries, 1);
-} go_regabi_regs_map SEC(".maps");
-// Copies the registers of the golang ABI, so that they can be
-// easily accessed using an offset.
-static __always_inline uint64_t* go_regabi_regs(const struct pt_regs* ctx) {
- __u32 zero = 0;
- struct go_regabi_regs_t* regs_heap_var = bpf_map_lookup_elem(&go_regabi_regs_map, &zero);
- if (regs_heap_var == NULL) {
- return NULL;
- }
-
- regs_heap_var->regs[0] = ctx->rax;
- regs_heap_var->regs[1] = ctx->rbx;
- regs_heap_var->regs[2] = ctx->rcx;
- regs_heap_var->regs[3] = ctx->rdi;
- regs_heap_var->regs[4] = ctx->rsi;
- regs_heap_var->regs[5] = ctx->r8;
- regs_heap_var->regs[6] = ctx->r9;
- regs_heap_var->regs[7] = ctx->r10;
- regs_heap_var->regs[8] = ctx->r11;
-
- return regs_heap_var->regs;
-}
-
-struct go_interface {
- int64_t type;
- void* ptr;
-};
-
-static __always_inline void assign_go_tls_arg(void* arg, size_t arg_size, struct go_tls_arg_location_t loc, const void* sp,
- uint64_t* regs) {
- // stack type
- if (loc.type == 1) {
- bpf_probe_read(arg, arg_size, sp + loc.offset);
- } else if (loc.type == 2) {
- // register type
- if (loc.offset >= 0 && loc.offset <= 30) {
- bpf_probe_read(arg, arg_size, (char*)regs + loc.offset);
- }
- }
-}
-
static __always_inline int get_fd_from_go_tls_conn(struct go_interface conn, struct go_tls_args_symaddr_t* symaddr) {
// read connection
bpf_probe_read(&conn, sizeof(conn), conn.ptr + symaddr->tls_conn_offset);
@@ -133,19 +46,4 @@ static __always_inline int get_fd_from_go_tls_conn(struct go_interface conn, str
__u64 sysfd;
bpf_probe_read(&sysfd, sizeof(sysfd), fd_ptr + symaddr->fd_sys_offset);
return sysfd;
-}
-
-struct {
- __uint(type, BPF_MAP_TYPE_HASH);
- __uint(max_entries, 1024);
- __type(key, __u64);
- __type(value, __u64);
-} go_tgid_goid_map SEC(".maps");
-static __inline __u64 get_goid(__u64 tgid) {
- __u64 *val;
- val = bpf_map_lookup_elem(&go_tgid_goid_map, &tgid);
- return !val ? 0 : *val;
-}
-static __inline void set_goid(__u64 tgid, __u64 goid) {
- bpf_map_update_elem(&go_tgid_goid_map, &tgid, &goid, 0);
}
\ No newline at end of file
diff --git a/bpf/profiling/network/netmonitor.c b/bpf/profiling/network/netmonitor.c
index 13abc00..1636cea 100644
--- a/bpf/profiling/network/netmonitor.c
+++ b/bpf/profiling/network/netmonitor.c
@@ -108,10 +108,6 @@ static __always_inline void submit_new_connection(struct pt_regs* ctx, __u32 fun
con.socket_family = AF_UNKNOWN;
}
- if (con.remote_port == 53) {
- bpf_printk("found the remote port is 53");
- }
-
// save to the active connection map
__u64 conid = gen_tgid_fd(tgid, fd);
struct socket_connect_event_t *event = create_socket_connect_event();
diff --git a/bpf/profiling/network/openssl.c b/bpf/profiling/network/openssl.c
index 0db64e0..ef09f73 100644
--- a/bpf/profiling/network/openssl.c
+++ b/bpf/profiling/network/openssl.c
@@ -16,6 +16,7 @@
// under the License.
#include "args.h"
+#include "symbol_offsets.h"
#include "openssl.h"
#include "node_tls.h"
@@ -36,7 +37,7 @@ static __inline void process_openssl_data(struct pt_regs* ctx, __u64 id, __u32 d
}
static int get_fd_symaddr(__u32 tgid, bool read, void* ssl) {
- struct openssl_fd_symaddr* addr = get_openssl_fd_symaddr(tgid);
+ struct openssl_symaddr* addr = get_openssl_symaddr(tgid);
if (addr == NULL) {
return -1;
}
diff --git a/bpf/profiling/network/openssl.h b/bpf/profiling/network/openssl.h
index 61e8425..3fa197d 100644
--- a/bpf/profiling/network/openssl.h
+++ b/bpf/profiling/network/openssl.h
@@ -15,21 +15,3 @@
// specific language governing permissions and limitations
// under the License.
-struct openssl_fd_symaddr {
- // read the BIO offset from ssl
- __u32 bio_read_offset;
- __u32 bio_write_offset;
- // read the fd offset from BIO
- __u32 fd_offset;
-};
-
-struct {
- __uint(type, BPF_MAP_TYPE_HASH);
- __uint(max_entries, 10000);
- __type(key, __u32);
- __type(value, struct openssl_fd_symaddr);
-} openssl_fd_symaddr_finder SEC(".maps");
-static __inline struct openssl_fd_symaddr* get_openssl_fd_symaddr(__u32 tgid) {
- struct openssl_fd_symaddr *addr = bpf_map_lookup_elem(&openssl_fd_symaddr_finder, &tgid);
- return addr;
-}
diff --git a/pkg/process/finders/base/tool.go b/pkg/process/finders/base/tool.go
index 408693c..749d4f6 100644
--- a/pkg/process/finders/base/tool.go
+++ b/pkg/process/finders/base/tool.go
@@ -25,9 +25,9 @@ import (
v3 "skywalking.apache.org/repo/goapi/collect/ebpf/profiling/process/v3"
"github.com/apache/skywalking-rover/pkg/process/api"
- "github.com/apache/skywalking-rover/pkg/tools"
"github.com/apache/skywalking-rover/pkg/tools/host"
"github.com/apache/skywalking-rover/pkg/tools/path"
+ process_tool "github.com/apache/skywalking-rover/pkg/tools/process"
"github.com/apache/skywalking-rover/pkg/tools/profiling"
"github.com/shirou/gopsutil/process"
@@ -41,7 +41,7 @@ func BuildProfilingStat(ps *process.Process) (*profiling.Info, error) {
}
// check support profiling
- return tools.ProcessProfilingStat(ps.Pid, exePath)
+ return process_tool.ProfilingStat(ps.Pid, exePath)
}
func tryToFindFileExecutePath(ps *process.Process) string {
diff --git a/pkg/profiling/continuous/checker/bpf/network/http1.go b/pkg/profiling/continuous/checker/bpf/network/http1.go
index 77ba21e..2a91647 100644
--- a/pkg/profiling/continuous/checker/bpf/network/http1.go
+++ b/pkg/profiling/continuous/checker/bpf/network/http1.go
@@ -66,7 +66,7 @@ func (h *HTTP1Analyzer) HandleBufferEvent(buffer *networkBufferInBPF) BufferEven
return nil
}
// clean the request buffer
- h.channelEvents[buffer.ChannelRef] = nil
+ delete(h.channelEvents, buffer.ChannelRef)
code, err := h.analyzeResponseStatus(buffer)
if err != nil {
diff --git a/pkg/profiling/continuous/checker/bpf/network/network.go b/pkg/profiling/continuous/checker/bpf/network/network.go
index 4bcda76..26bdded 100644
--- a/pkg/profiling/continuous/checker/bpf/network/network.go
+++ b/pkg/profiling/continuous/checker/bpf/network/network.go
@@ -18,6 +18,7 @@
package network
import (
+ "os"
"sync"
"time"
@@ -39,11 +40,11 @@ var log = logger.GetLogger("profiling", "continuous", "checker", "network", "bpf
var locker sync.Mutex
var bpf *bpfObjects
var bpfLinker *btf.Linker
-var monitoringProcesses map[int32]map[string]bool
+var monitoringProcesses map[int32]*monitoringProcessInfo
var notifiers []EventNotify
func init() {
- monitoringProcesses = make(map[int32]map[string]bool)
+ monitoringProcesses = make(map[int32]*monitoringProcessInfo)
}
type BufferEvent interface {
@@ -69,21 +70,21 @@ func AddWatchProcess(pid int32, from string) error {
return e
}
- // first, update to the monitor control
- if e := bpf.ProcessMonitorControl.Update(uint32(pid), uint32(1), ebpf.UpdateAny); e != nil {
- // if add failure, then check the BPF should be shutdown or not
- _ = shutdownBPFIfNoProcesses()
- return e
- }
-
- // then, add to the monitoring cache
+ // adding to the cache
monitoring := monitoringProcesses[pid]
if monitoring == nil {
- monitoring = make(map[string]bool)
+ monitoring = newMonitoringProcessInfo(pid)
monitoringProcesses[pid] = monitoring
}
- monitoring[from] = true
+ // start monitoring process
+ if e := monitoring.AddSource(from); e != nil {
+ // remove the source if add failure
+ if deleteProcess, _ := monitoring.RemoveSource(from); deleteProcess {
+ delete(monitoringProcesses, pid)
+ }
+ return e
+ }
return nil
}
@@ -100,23 +101,27 @@ func RemoveWatchProcess(pid int32, from string) error {
return nil
}
- delete(monitoring, from)
- shouldRemoveMonitor := false
- if len(monitoringProcesses[pid]) == 0 {
+ deleteProcess, err := monitoring.RemoveSource(from)
+ if deleteProcess {
delete(monitoringProcesses, pid)
- shouldRemoveMonitor = true
- }
-
- if shouldRemoveMonitor {
- if err := bpf.ProcessMonitorControl.Delete(uint32(pid)); err != nil {
- return err
- }
}
- return nil
+ return err
}
func ForceShutdownBPF() error {
- return shutdownBPF()
+ // shutdown all processes
+ var err error
+ for _, p := range monitoringProcesses {
+ if e := p.Shutdown(); e != nil {
+ err = multierror.Append(err, e)
+ }
+ }
+ // shutdown the main BPF
+ monitoringProcesses = make(map[int32]*monitoringProcessInfo)
+ if e := shutdownBPF(); e != nil {
+ err = multierror.Append(err, e)
+ }
+ return err
}
// start the BPF program if contains process that needs monitor
@@ -142,7 +147,7 @@ func startBPFIfNeed() error {
n.ReceiveBufferEvent(event)
}
})
- bpfLinker.ReadEventAsync(bpf.SocketBufferSendQueue, reader.Read, reader.BufferDataBPFSupplier)
+ bpfLinker.ReadEventAsyncWithBufferSize(bpf.SocketBufferSendQueue, reader.Read, os.Getpagesize()*100, reader.BufferDataBPFSupplier)
if err := bpfLinker.HasError(); err != nil {
_ = bpfLinker.Close()
diff --git a/pkg/profiling/continuous/checker/bpf/network/process.go b/pkg/profiling/continuous/checker/bpf/network/process.go
new file mode 100644
index 0000000..f2447bc
--- /dev/null
+++ b/pkg/profiling/continuous/checker/bpf/network/process.go
@@ -0,0 +1,82 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package network
+
+import (
+ "github.com/cilium/ebpf"
+
+ "github.com/apache/skywalking-rover/pkg/tools/btf"
+
+ "github.com/hashicorp/go-multierror"
+)
+
+type monitoringProcessInfo struct {
+ pid int32
+ linker *btf.Linker
+ source map[string]bool
+}
+
+func newMonitoringProcessInfo(pid int32) *monitoringProcessInfo {
+ return &monitoringProcessInfo{
+ pid: pid,
+ linker: btf.NewLinker(),
+ source: make(map[string]bool),
+ }
+}
+
+func (m *monitoringProcessInfo) AddSource(from string) error {
+ // if already have source, then just added
+ if len(m.source) != 0 {
+ m.source[from] = true
+ }
+
+ // start the TLS first
+ if err := addSSLProcess(int(m.pid), m.linker, bpf); err != nil {
+ return err
+ }
+
+ // add to the process control
+ if e := bpf.ProcessMonitorControl.Update(uint32(m.pid), uint32(1), ebpf.UpdateAny); e != nil {
+ return e
+ }
+ m.source[from] = true
+ return nil
+}
+
+func (m *monitoringProcessInfo) RemoveSource(from string) (bool, error) {
+ delete(m.source, from)
+
+ // if still have source monitoring, then just ignore to shut down process monitoring
+ if len(m.source) > 0 {
+ return false, nil
+ }
+
+ var err error
+ if e := m.linker.Close(); e != nil {
+ err = multierror.Append(err, e)
+ }
+ if e := bpf.ProcessMonitorControl.Delete(uint32(m.pid)); e != nil {
+ err = multierror.Append(err, e)
+ }
+
+ return true, err
+}
+
+func (m *monitoringProcessInfo) Shutdown() error {
+ return m.linker.Close()
+}
diff --git a/pkg/profiling/continuous/checker/bpf/network/reader.go b/pkg/profiling/continuous/checker/bpf/network/reader.go
index 7530e5c..c5893f0 100644
--- a/pkg/profiling/continuous/checker/bpf/network/reader.go
+++ b/pkg/profiling/continuous/checker/bpf/network/reader.go
@@ -42,7 +42,7 @@ type networkBufferInBPF struct {
Direction BufferDirection
Size uint16
Pid uint32
- Buffer [159]byte
+ Buffer [256]byte
}
type networkBufferReader struct {
diff --git a/bpf/profiling/network/openssl.h b/pkg/profiling/continuous/checker/bpf/network/ssl.go
similarity index 51%
copy from bpf/profiling/network/openssl.h
copy to pkg/profiling/continuous/checker/bpf/network/ssl.go
index 61e8425..50261f4 100644
--- a/bpf/profiling/network/openssl.h
+++ b/pkg/profiling/continuous/checker/bpf/network/ssl.go
@@ -15,21 +15,24 @@
// specific language governing permissions and limitations
// under the License.
-struct openssl_fd_symaddr {
- // read the BIO offset from ssl
- __u32 bio_read_offset;
- __u32 bio_write_offset;
- // read the fd offset from BIO
- __u32 fd_offset;
-};
-
-struct {
- __uint(type, BPF_MAP_TYPE_HASH);
- __uint(max_entries, 10000);
- __type(key, __u32);
- __type(value, struct openssl_fd_symaddr);
-} openssl_fd_symaddr_finder SEC(".maps");
-static __inline struct openssl_fd_symaddr* get_openssl_fd_symaddr(__u32 tgid) {
- struct openssl_fd_symaddr *addr = bpf_map_lookup_elem(&openssl_fd_symaddr_finder, &tgid);
- return addr;
+package network
+
+import (
+ "github.com/apache/skywalking-rover/pkg/tools/btf"
+ "github.com/apache/skywalking-rover/pkg/tools/ssl"
+)
+
+func addSSLProcess(pid int, linker *btf.Linker, bpf *bpfObjects) error {
+ register := ssl.NewSSLRegister(pid, linker)
+
+ register.OpenSSL(bpf.OpensslSymaddrMap, bpf.OpensslWrite, bpf.OpensslWriteRet, bpf.OpensslRead, bpf.OpensslReadRet)
+
+ register.Envoy(bpf.EnvoyTlsArgsSymaddrMap, bpf.OpensslWrite, bpf.OpensslWriteRet, bpf.OpensslRead, bpf.OpensslReadRet)
+
+ register.GoTLS(bpf.GoTlsArgsSymaddrMap, bpf.GoCasgstatus, bpf.GoTlsWrite, bpf.GoTlsWriteRet, bpf.GoTlsRead, bpf.GoTlsReadRet)
+
+ register.Node(bpf.OpensslSymaddrMap, nil, bpf.OpensslWrite, bpf.OpensslWriteRet, bpf.OpensslRead, bpf.OpensslReadRet,
+ nil, nil, nil)
+
+ return register.Execute()
}
diff --git a/pkg/profiling/task/network/analyze/base/enums.go b/pkg/profiling/task/network/analyze/base/enums.go
index ad4aa60..04173dc 100644
--- a/pkg/profiling/task/network/analyze/base/enums.go
+++ b/pkg/profiling/task/network/analyze/base/enums.go
@@ -111,13 +111,6 @@ func (c ConnectionProtocol) String() string {
}
}
-type GoTLSArgsLocationType uint32
-
-const (
- GoTLSArgsLocationTypeStack GoTLSArgsLocationType = 1
- GoTLSArgsLocationTypeRegister GoTLSArgsLocationType = 2
-)
-
type SocketMessageType uint8
const (
diff --git a/pkg/profiling/task/network/ssl.go b/pkg/profiling/task/network/ssl.go
index 5591d53..d3fd33e 100644
--- a/pkg/profiling/task/network/ssl.go
+++ b/pkg/profiling/task/network/ssl.go
@@ -18,600 +18,21 @@
package network
import (
- "bytes"
- "encoding/binary"
- "fmt"
- "os/exec"
- "regexp"
- "strconv"
- "strings"
-
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/bpf"
- "github.com/apache/skywalking-rover/pkg/tools"
- "github.com/apache/skywalking-rover/pkg/tools/btf"
- "github.com/apache/skywalking-rover/pkg/tools/elf"
- "github.com/apache/skywalking-rover/pkg/tools/host"
- "github.com/apache/skywalking-rover/pkg/tools/path"
- "github.com/apache/skywalking-rover/pkg/tools/profiling"
- "github.com/apache/skywalking-rover/pkg/tools/version"
-)
-
-var (
- openSSLVersionRegex = regexp.MustCompile(`^OpenSSL\s+(?P<Major>\d)\.(?P<Minor>\d)\.(?P<Fix>\d+)\w?\s+`)
- goVersionRegex = regexp.MustCompile(`^go(?P<Major>\d)\.(?P<Minor>\d+)`)
- goTLSWriteSymbol = "crypto/tls.(*Conn).Write"
- goTLSReadSymbol = "crypto/tls.(*Conn).Read"
- goTLSGIDStatusSymbol = "runtime.casgstatus"
- goTLSPollFDSymbol = "internal/poll.FD"
- goTLSConnSymbol = "crypto/tls.Conn"
- goTLSRuntimeG = "runtime.g"
- nodeVersionRegex = regexp.MustCompile(`^node\.js/v(?P<Major>\d+)\.(?P<Minor>\d+)\.(?P<Patch>\d+)$`)
+ "github.com/apache/skywalking-rover/pkg/tools/ssl"
)
-type OpenSSLFdSymAddrConfigInBPF struct {
- BIOReadOffset uint32
- BIOWriteOffset uint32
- FDOffset uint32
-}
-
func addSSLProcess(pid int, loader *bpf.Loader) error {
- modules, err := tools.ProcessModules(int32(pid))
- if err != nil {
- return fmt.Errorf("read process modules error: %d, error: %v", pid, err)
- }
-
- // openssl process
- if err1 := processOpenSSLProcess(pid, loader, modules); err1 != nil {
- return err1
- }
-
- // envoy with boring ssl
- if err1 := processEnvoyProcess(pid, loader, modules); err1 != nil {
- return err1
- }
-
- // GoTLS
- if err1 := processGoProcess(pid, loader, modules); err1 != nil {
- return err1
- }
-
- // Nodejs
- if err1 := processNodeProcess(pid, loader, modules); err1 != nil {
- return err1
- }
-
- return nil
-}
-
-func processOpenSSLProcess(pid int, loader *bpf.Loader, modules []*profiling.Module) error {
- var libcryptoName, libsslName = "libcrypto.so", "libssl.so"
- var libcryptoPath, libsslPath string
- processModules, err := findProcessModules(modules, libcryptoName, libsslName)
- if err != nil {
- return err
- }
- // the openssl not exists, so ignore
- if len(processModules) == 0 {
- return nil
- }
- if libcrypto := processModules[libcryptoName]; libcrypto != nil {
- libcryptoPath = libcrypto.Path
- }
- if libssl := processModules[libsslName]; libssl != nil {
- libsslPath = libssl.Path
- }
- if libcryptoPath == "" || libsslPath == "" {
- return fmt.Errorf("the OpenSSL library not complete, libcrypto: %s, libssl: %s", libcryptoPath, libsslPath)
- }
-
- // build the symbol address config and write to the bpf
- conf, err := buildSSLSymAddrConfig(libcryptoPath)
- if err != nil {
- return err
- }
- if err := loader.OpensslFdSymaddrFinder.Put(uint32(pid), conf); err != nil {
- return err
- }
-
- // attach the linker
- return processOpenSSLModule(loader, processModules[libsslName])
-}
-
-func processOpenSSLModule(loader *bpf.Loader, libSSLModule *profiling.Module) error {
- libSSLLinker := loader.OpenUProbeExeFile(libSSLModule.Path)
- libSSLLinker.AddLink("SSL_write", loader.OpensslWrite, loader.OpensslWriteRet)
- libSSLLinker.AddLink("SSL_read", loader.OpensslRead, loader.OpensslReadRet)
- return loader.HasError()
-}
-
-func processEnvoyProcess(_ int, loader *bpf.Loader, modules []*profiling.Module) error {
- moduleName := "/envoy"
- processModules, err := findProcessModules(modules, moduleName)
- if err != nil {
- return err
- }
- envoyModule := processModules[moduleName]
- if envoyModule == nil {
- return nil
- }
- var readSymbol, writeSymbol bool
- for _, sym := range envoyModule.Symbols {
- if sym.Name == "SSL_read" {
- readSymbol = true
- } else if sym.Name == "SSL_write" {
- writeSymbol = true
- }
- }
- if !readSymbol || !writeSymbol {
- log.Debugf("found the envoy process, but the ssl read or write symbol not exists, so ignore. read: %t, write: %t",
- readSymbol, writeSymbol)
- return nil
- }
-
- log.Debugf("found current module is envoy, so attach to the SSL read and write")
-
- // attach the linker
- libSSLLinker := loader.OpenUProbeExeFile(envoyModule.Path)
- libSSLLinker.AddLink("SSL_write", loader.OpensslWrite, loader.OpensslWriteRet)
- libSSLLinker.AddLink("SSL_read", loader.OpensslRead, loader.OpensslReadRet)
- return loader.HasError()
-}
-
-type SymbolLocation struct {
- Type base.GoTLSArgsLocationType
- Offset uint32
-}
-
-type GoTLSSymbolAddresses struct {
- // net.Conn addresses
- FDSysFDOffset uint64
- TLSConnOffset uint64
- GIDOffset uint64
- TCPConnOffset uint64
-
- // casgstatus(goroutine status change) function relate locations
- CasgStatusGPLoc SymbolLocation
- CasgStatusNEWValLoc SymbolLocation
-
- // write function relate locations
- WriteConnectionLoc SymbolLocation
- WriteBufferLoc SymbolLocation
- WriteRet0Loc SymbolLocation
- WriteRet1Loc SymbolLocation
-
- // write function relate locations
- ReadConnectionLoc SymbolLocation
- ReadBufferLoc SymbolLocation
- ReadRet0Loc SymbolLocation
- ReadRet1Loc SymbolLocation
-}
-
-type GoStringInC struct {
- Ptr uint64
- Size uint64
-}
+ register := ssl.NewSSLRegister(pid, loader.Linker)
-func processGoProcess(pid int, loader *bpf.Loader, modules []*profiling.Module) error {
- // check current process is go program
- buildVersionSymbol := searchSymbol(modules, func(a, b string) bool {
- return a == b
- }, "runtime.buildVersion")
- if buildVersionSymbol == nil {
- log.Debugf("current process is not Go program, so won't add the GoTLS protos. pid: %d", pid)
- return nil
- }
- pidExeFile := host.GetFileInHost(fmt.Sprintf("/proc/%d/exe", pid))
- elfFile, err := elf.NewFile(pidExeFile)
- if err != nil {
- return fmt.Errorf("read executable file error: %v", err)
- }
- defer elfFile.Close()
+ register.OpenSSL(loader.OpensslSymaddrMap, loader.OpensslWrite, loader.OpensslWriteRet, loader.OpensslRead, loader.OpensslReadRet)
- v, err := getGoVersion(elfFile, buildVersionSymbol)
- if err != nil {
- return err
- }
+ register.Envoy(nil, loader.OpensslWrite, loader.OpensslWriteRet, loader.OpensslRead, loader.OpensslReadRet)
- // generate symbol offsets
- symbolConfig, elfFile, err := generateGOTLSSymbolOffsets(modules, pid, elfFile, v)
- if err != nil {
- return err
- }
- if symbolConfig == nil || elfFile == nil {
- return nil
- }
-
- // setting the locations
- if err := loader.GoTlsArgsSymaddrMap.Put(uint32(pid), symbolConfig); err != nil {
- return fmt.Errorf("setting the Go TLS argument location failure, pid: %d, error: %v", pid, err)
- }
-
- // uprobes
- exeFile := loader.OpenUProbeExeFile(pidExeFile)
- exeFile.AddLinkWithType("runtime.casgstatus", true, loader.GoCasgstatus)
- exeFile.AddGoLink(goTLSWriteSymbol, loader.GoTlsWrite, loader.GoTlsWriteRet, elfFile)
- exeFile.AddGoLink(goTLSReadSymbol, loader.GoTlsRead, loader.GoTlsReadRet, elfFile)
-
- return loader.HasError()
-}
-
-func processNodeProcess(pid int, loader *bpf.Loader, modules []*profiling.Module) error {
- moduleName1, moduleName2, libsslName := "/nodejs", "/node", "libssl.so"
- processModules, err := findProcessModules(modules, moduleName1, moduleName2, libsslName)
- if err != nil {
- return err
- }
- nodeModule := processModules[moduleName1]
- libsslModule := processModules[libsslName]
- needsReAttachSSL := false
- if nodeModule == nil {
- nodeModule = processModules[moduleName2]
- }
- if nodeModule == nil {
- log.Debugf("current process is not nodejs program, so won't add the nodejs protos. pid: %d", pid)
- return nil
- }
- if libsslModule == nil {
- if searchSymbol([]*profiling.Module{nodeModule}, func(a, b string) bool {
- return a == b
- }, "SSL_read") == nil || searchSymbol([]*profiling.Module{nodeModule}, func(a, b string) bool {
- return a == b
- }, "SSL_write") == nil {
- log.Warnf("could not found the SSL_read/SSL_write under the nodejs program, so ignore. pid: %d", pid)
- return nil
- }
- libsslModule = nodeModule
- needsReAttachSSL = true
- }
- v, err := getNodeVersion(nodeModule.Path)
- if err != nil {
- return fmt.Errorf("read nodejs version failure, pid: %d, error: %v", pid, err)
- }
- log.Debugf("read the nodejs version, pid: %d, version: %s", pid, v)
- config, err := findNodeTLSAddrConfig(v)
- if err != nil {
- return err
- }
- // setting the locations
- if err := loader.NodeTlsSymaddrMap.Put(uint32(pid), config); err != nil {
- return fmt.Errorf("setting the node TLS location failure, pid: %d, error: %v", pid, err)
- }
- // register node tls
- if err := registerNodeTLSProbes(v, loader, nodeModule, libsslModule); err != nil {
- return fmt.Errorf("register node TLS probes failure, pid: %d, error: %v", pid, err)
- }
- // attach the OpenSSL Probe if needs
- if needsReAttachSSL {
- return processOpenSSLModule(loader, libsslModule)
- }
- return nil
-}
-
-var nodeTLSAddrWithVersions = []struct {
- v *version.Version
- conf *NodeTLSAddrInBPF
-}{
- {version.Build(10, 19, 0), &NodeTLSAddrInBPF{0x0130, 0x08, 0x00, 0x50, 0x90, 0x88, 0x30}},
- {version.Build(12, 3, 1), &NodeTLSAddrInBPF{0x0130, 0x08, 0x00, 0x50, 0x90, 0x88, 0x30}},
- {version.Build(12, 16, 2), &NodeTLSAddrInBPF{0x0138, 0x08, 0x00, 0x58, 0x98, 0x88, 0x30}},
- {version.Build(13, 0, 0), &NodeTLSAddrInBPF{0x0130, 0x08, 0x00, 0x50, 0x90, 0x88, 0x30}},
- {version.Build(13, 2, 0), &NodeTLSAddrInBPF{0x0130, 0x08, 0x00, 0x58, 0x98, 0x88, 0x30}},
- {version.Build(13, 10, 1), &NodeTLSAddrInBPF{0x0140, 0x08, 0x00, 0x60, 0xa0, 0x88, 0x30}},
- {version.Build(14, 5, 0), &NodeTLSAddrInBPF{0x138, 0x08, 0x00, 0x58, 0x98, 0x88, 0x30}},
- {version.Build(15, 0, 0), &NodeTLSAddrInBPF{0x78, 0x08, 0x00, 0x58, 0x98, 0x88, 0x30}},
-}
-
-var nodeTLSProbeWithVersions = []struct {
- v *version.Version
- f func(uprobe *btf.UProbeExeFile, bpf *bpf.Loader, nodeModule *profiling.Module)
-}{
- {version.Build(10, 19, 0), func(uprobe *btf.UProbeExeFile, bpf *bpf.Loader, nodeModule *profiling.Module) {
- uprobe.AddLinkWithSymbols(searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node7TLSWrapC2E"),
- bpf.NodeTlsWrap, bpf.NodeTlsWrapRet)
- uprobe.AddLinkWithSymbols(searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node7TLSWrap7ClearInE"),
- bpf.NodeTlsWrap, bpf.NodeTlsWrapRet)
- uprobe.AddLinkWithSymbols(searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node7TLSWrap8ClearOutE"),
- bpf.NodeTlsWrap, bpf.NodeTlsWrapRet)
- }},
- {version.Build(15, 0, 0), func(uprobe *btf.UProbeExeFile, bpf *bpf.Loader, nodeModule *profiling.Module) {
- uprobe.AddLinkWithSymbols(searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node6crypto7TLSWrapC2E"),
- bpf.NodeTlsWrap, bpf.NodeTlsWrapRet)
- uprobe.AddLinkWithSymbols(searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node6crypto7TLSWrap7ClearInE"),
- bpf.NodeTlsWrap, bpf.NodeTlsWrapRet)
- uprobe.AddLinkWithSymbols(searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node6crypto7TLSWrap8ClearOutE"),
- bpf.NodeTlsWrap, bpf.NodeTlsWrapRet)
- }},
-}
+ register.GoTLS(loader.GoTlsArgsSymaddrMap, loader.GoCasgstatus, loader.GoTlsWrite, loader.GoTlsWriteRet, loader.GoTlsRead, loader.GoTlsReadRet)
-type NodeTLSAddrInBPF struct {
- TLSWrapStreamListenerOffset uint32
- StreamListenerStreamOffset uint32
- StreamBaseStreamResourceOffset uint32
- LibuvStreamWrapStreamBaseOffset uint32
- LibuvStreamWrapStreamOffset uint32
- UVStreamSIOWatcherOffset uint32
- UVIOSFDOffset uint32
-}
-
-func findNodeTLSAddrConfig(v *version.Version) (*NodeTLSAddrInBPF, error) {
- var lastest *NodeTLSAddrInBPF
- for _, c := range nodeTLSAddrWithVersions {
- if v.GreaterOrEquals(c.v) {
- lastest = c.conf
- }
- }
- if lastest != nil {
- return lastest, nil
- }
- return nil, fmt.Errorf("could not support version: %s", v)
-}
-
-func registerNodeTLSProbes(v *version.Version, loader *bpf.Loader, nodeModule, libSSLModule *profiling.Module) error {
- var probeFunc func(uprobe *btf.UProbeExeFile, bpf *bpf.Loader, nodeModule *profiling.Module)
- for _, c := range nodeTLSProbeWithVersions {
- if v.GreaterOrEquals(c.v) {
- probeFunc = c.f
- }
- }
- if probeFunc == nil {
- return fmt.Errorf("the version is not support: %v", v)
- }
- file := loader.OpenUProbeExeFile(nodeModule.Path)
- probeFunc(file, loader, nodeModule)
-
- // find the SSL_new, and register
- file = loader.OpenUProbeExeFile(libSSLModule.Path)
- file.AddLinkWithType("SSL_new", false, loader.NodeTlsRetSsl)
- return loader.HasError()
-}
-
-func getNodeVersion(p string) (*version.Version, error) {
- result, err := exec.Command("strings", p).Output()
- if err != nil {
- return nil, err
- }
- for _, d := range strings.Split(string(result), "\n") {
- versionInfo := nodeVersionRegex.FindStringSubmatch(strings.TrimSpace(d))
- if len(versionInfo) != 4 {
- continue
- }
- return version.Read(versionInfo[1], versionInfo[2], versionInfo[3])
- }
-
- return nil, fmt.Errorf("nodejs version is not found")
-}
-
-func getGoVersion(elfFile *elf.File, versionSymbol *profiling.Symbol) (*version.Version, error) {
- buffer, err := elfFile.ReadSymbolData(".data", versionSymbol.Location, versionSymbol.Size)
- if err != nil {
- return nil, fmt.Errorf("reading go version struct info failure: %v", err)
- }
- var t = GoStringInC{}
- buf := bytes.NewReader(buffer)
- err = binary.Read(buf, binary.LittleEndian, &t)
- if err != nil {
- return nil, fmt.Errorf("read the go structure failure: %v", err)
- }
- buffer, err = elfFile.ReadSymbolData(".data", t.Ptr, t.Size)
- if err != nil {
- return nil, fmt.Errorf("read the go version failure: %v", err)
- }
-
- // parse versions
- submatch := goVersionRegex.FindStringSubmatch(string(buffer))
- if len(submatch) != 3 {
- return nil, fmt.Errorf("the go version is failure to identify, version: %s", string(buffer))
- }
- return version.Read(submatch[1], submatch[2], "")
-}
-
-func generateGOTLSSymbolOffsets(modules []*profiling.Module, _ int, elfFile *elf.File, v *version.Version) (*GoTLSSymbolAddresses, *elf.File, error) {
- reader, err := elfFile.NewDwarfReader(
- goTLSReadSymbol, goTLSWriteSymbol, goTLSGIDStatusSymbol,
- goTLSPollFDSymbol, goTLSConnSymbol, goTLSRuntimeG)
- if err != nil {
- return nil, nil, err
- }
-
- symbolAddresses := &GoTLSSymbolAddresses{}
-
- sym := searchSymbol(modules, func(a, b string) bool {
- return a == b
- }, "go.itab.*net.TCPConn,net.Conn")
- if sym == nil {
- log.Warnf("could not found the tcp connection symbol: go.itab.*net.TCPConn,net.Conn")
- return nil, nil, nil
- }
- symbolAddresses.TCPConnOffset = sym.Location
-
- readFunction := reader.GetFunction(goTLSReadSymbol)
- if readFunction == nil {
- log.Warnf("could not found the go tls read symbol: %s", goTLSReadSymbol)
- return nil, nil, nil
- }
- writeFunction := reader.GetFunction(goTLSWriteSymbol)
- if writeFunction == nil {
- log.Warnf("could not found the go tls write symbol: %s", goTLSWriteSymbol)
- return nil, nil, nil
- }
- gidStatusFunction := reader.GetFunction(goTLSGIDStatusSymbol)
- if gidStatusFunction == nil {
- log.Warnf("could not found the goid status change symbol: %s", goTLSGIDStatusSymbol)
- return nil, nil, nil
- }
-
- var retValArg0, retValArg1 = "~r1", "~r2"
- if v.Minor >= 18 {
- retValArg0, retValArg1 = "~r0", "~r1"
- }
-
- // build the symbols
- var assignError error
- // offset
- assignError = assignGoTLSStructureOffset(assignError, reader, goTLSPollFDSymbol, "Sysfd", &symbolAddresses.FDSysFDOffset)
- assignError = assignGoTLSStructureOffset(assignError, reader, goTLSConnSymbol, "conn", &symbolAddresses.TLSConnOffset)
- assignError = assignGoTLSStructureOffset(assignError, reader, goTLSRuntimeG, "goid", &symbolAddresses.GIDOffset)
-
- // gid status change
- assignError = assignGoTLSArgsLocation(assignError, gidStatusFunction, "gp", &symbolAddresses.CasgStatusGPLoc)
- assignError = assignGoTLSArgsLocation(assignError, gidStatusFunction, "newval", &symbolAddresses.CasgStatusNEWValLoc)
-
- // write
- assignError = assignGoTLSArgsLocation(assignError, writeFunction, "c", &symbolAddresses.WriteConnectionLoc)
- assignError = assignGoTLSArgsLocation(assignError, writeFunction, "b", &symbolAddresses.WriteBufferLoc)
- assignError = assignGoTLSArgsLocation(assignError, writeFunction, retValArg0, &symbolAddresses.WriteRet0Loc)
- assignError = assignGoTLSArgsLocation(assignError, writeFunction, retValArg1, &symbolAddresses.WriteRet1Loc)
- // read
- assignError = assignGoTLSArgsLocation(assignError, readFunction, "c", &symbolAddresses.ReadConnectionLoc)
- assignError = assignGoTLSArgsLocation(assignError, readFunction, "b", &symbolAddresses.ReadBufferLoc)
- assignError = assignGoTLSArgsLocation(assignError, readFunction, retValArg0, &symbolAddresses.ReadRet0Loc)
- assignError = assignGoTLSArgsLocation(assignError, readFunction, retValArg1, &symbolAddresses.ReadRet1Loc)
-
- return symbolAddresses, elfFile, assignError
-}
-
-func assignGoTLSStructureOffset(err error, reader *elf.DwarfReader, structName, fieldName string, dest *uint64) error {
- if err != nil {
- return err
- }
- structure := reader.GetStructure(structName)
- if structure == nil {
- return fmt.Errorf("the structure is not found, name: %s", structName)
- }
- field := structure.GetField(fieldName)
- if field == nil {
- return fmt.Errorf("the field is not found in structure, structure name: %s, field name: %s", structName, fieldName)
- }
- *dest = uint64(field.Offset)
- return nil
-}
-
-func assignGoTLSArgsLocation(err error, function *elf.FunctionInfo, argName string, dest *SymbolLocation) error {
- if err != nil {
- return err
- }
- var kSPOffset uint32 = 8
- args := function.Args(argName)
- if args == nil {
- return fmt.Errorf("the args is not found, function: %s, args name: %s", function.Name(), argName)
- }
- if args.Location.Type == elf.ArgLocationTypeStack {
- dest.Type = base.GoTLSArgsLocationTypeStack
- dest.Offset = uint32(args.Location.Offset) + kSPOffset
- } else if args.Location.Type == elf.ArgLocationTypeRegister {
- dest.Type = base.GoTLSArgsLocationTypeRegister
- dest.Offset = uint32(args.Location.Offset)
- } else {
- return fmt.Errorf("the location type is not support, function: %s, args name: %s, type: %d",
- function.Name(), argName, args.Location.Type)
- }
- return nil
-}
-
-func findProcessModules(modules []*profiling.Module, moduleNames ...string) (map[string]*profiling.Module, error) {
- result := make(map[string]*profiling.Module)
- for _, mod := range modules {
- for _, modName := range moduleNames {
- if strings.Contains(mod.Name, modName) {
- if !path.Exists(mod.Path) {
- return nil, fmt.Errorf("the module path not exists, path: %s", mod.Path)
- }
- result[modName] = mod
- }
- }
- }
- return result, nil
-}
-
-func buildSSLSymAddrConfig(libcryptoPath string) (*OpenSSLFdSymAddrConfigInBPF, error) {
- // using "strings" command to query the symbol in the libcrypto library
- result, err := exec.Command("strings", libcryptoPath).Output()
- if err != nil {
- return nil, err
- }
- for _, p := range strings.Split(string(result), "\n") {
- submatch := openSSLVersionRegex.FindStringSubmatch(p)
- if len(submatch) != 4 {
- continue
- }
- major := submatch[1]
- minor := submatch[2]
- fix := submatch[3]
-
- log.Debugf("found the libcrypto.so version: %s.%s.%s", major, minor, fix)
- conf := &OpenSSLFdSymAddrConfigInBPF{}
-
- // must be number, already validate in the regex
- majorVal, _ := strconv.Atoi(major)
- minorVal, _ := strconv.Atoi(minor)
- fixVal, _ := strconv.Atoi(fix)
-
- // max support version is 3.0.x
- if majorVal > 3 || (majorVal == 3 && minorVal > 0) {
- return nil, fmt.Errorf("the version of the libcrypto is not support: %s.%s.%s", major, minor, fix)
- }
-
- // bio offset
- // https://github.com/openssl/openssl/blob/OpenSSL_1_0_0-stable/ssl/ssl.h#L1093-L1111
- // https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/ssl/ssl_local.h#L1068-L1083
- // https://github.com/openssl/openssl/blob/openssl-3.0.7/ssl/ssl_local.h#L1212-L1227
- conf.BIOReadOffset = 16
- conf.BIOWriteOffset = 24
- // fd offset
- if majorVal == 3 && minorVal == 0 {
- // 3.0.x
- // https://github.com/openssl/openssl/blob/openssl-3.0.7/crypto/bio/bio_local.h#L115-L128
- // OPENSSL_NO_DEPRECATED_3_0 is not defined by default unless the user pass the specific build option
- conf.FDOffset = 56
- } else if (minorVal == 0) || (minorVal == 1 && fixVal == 0) {
- // 1.0.x || 1.1.0
- // https://github.com/openssl/openssl/blob/OpenSSL_1_0_0-stable/crypto/bio/bio.h#L297-L306
- conf.FDOffset = 40
- } else {
- // 1.1.1
- // https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/crypto/bio/bio_local.h#L115-L125
- conf.FDOffset = 48
- }
- log.Debugf("the lobcrypto.so library symbol verson config, version: %s.%s.%s, bio offset: %d",
- major, minor, fix, conf.FDOffset)
- return conf, nil
- }
- return nil, fmt.Errorf("could not fount the version of the libcrypto.so")
-}
-
-type stringVerify func(a, b string) bool
-
-func searchSymbolNames(modules []*profiling.Module, verify stringVerify, values ...string) []string {
- list := searchSymbolList(modules, verify, values...)
- if len(list) > 0 {
- result := make([]string, 0)
- for _, i := range list {
- result = append(result, i.Name)
- }
- return result
- }
- return nil
-}
-
-func searchSymbol(modules []*profiling.Module, verify stringVerify, values ...string) *profiling.Symbol {
- list := searchSymbolList(modules, verify, values...)
- if len(list) > 0 {
- return list[0]
- }
- return nil
-}
+ register.Node(nil, loader.NodeTlsSymaddrMap, loader.OpensslWrite, loader.OpensslWriteRet, loader.OpensslRead, loader.OpensslReadRet,
+ loader.NodeTlsRetSsl, loader.NodeTlsWrap, loader.NodeTlsWrapRet)
-func searchSymbolList(modules []*profiling.Module, verify stringVerify, values ...string) []*profiling.Symbol {
- var result []*profiling.Symbol
- for _, mod := range modules {
- for _, s := range mod.Symbols {
- for _, validator := range values {
- if verify(s.Name, validator) {
- result = append(result, s)
- }
- }
- }
- }
- return result
+ return register.Execute()
}
diff --git a/pkg/profiling/task/offcpu/runner.go b/pkg/profiling/task/offcpu/runner.go
index 149747e..9c8c7e9 100644
--- a/pkg/profiling/task/offcpu/runner.go
+++ b/pkg/profiling/task/offcpu/runner.go
@@ -32,8 +32,8 @@ import (
"github.com/apache/skywalking-rover/pkg/module"
"github.com/apache/skywalking-rover/pkg/process/api"
"github.com/apache/skywalking-rover/pkg/profiling/task/base"
- "github.com/apache/skywalking-rover/pkg/tools"
"github.com/apache/skywalking-rover/pkg/tools/btf"
+ "github.com/apache/skywalking-rover/pkg/tools/process"
"github.com/apache/skywalking-rover/pkg/tools/profiling"
v3 "skywalking.apache.org/repo/goapi/collect/ebpf/profiling/v3"
@@ -80,10 +80,10 @@ func (r *Runner) Init(task *base.ProfilingTask, processes []api.ProcessInterface
if len(processes) != 1 {
return fmt.Errorf("the processes count must be 1, current is: %d", len(processes))
}
- process := processes[0]
- r.pid = process.Pid()
- r.processProfiling = process.ProfilingStat()
- kernelProfiling, err := tools.KernelFileProfilingStat()
+ curProcess := processes[0]
+ r.pid = curProcess.Pid()
+ r.processProfiling = curProcess.ProfilingStat()
+ kernelProfiling, err := process.KernelFileProfilingStat()
if err != nil {
log.Warnf("could not analyze kernel profiling stats: %v", err)
}
diff --git a/pkg/profiling/task/oncpu/runner.go b/pkg/profiling/task/oncpu/runner.go
index b346372..01287f6 100644
--- a/pkg/profiling/task/oncpu/runner.go
+++ b/pkg/profiling/task/oncpu/runner.go
@@ -31,7 +31,7 @@ import (
"github.com/apache/skywalking-rover/pkg/module"
"github.com/apache/skywalking-rover/pkg/process/api"
"github.com/apache/skywalking-rover/pkg/profiling/task/base"
- "github.com/apache/skywalking-rover/pkg/tools"
+ "github.com/apache/skywalking-rover/pkg/tools/process"
"github.com/apache/skywalking-rover/pkg/tools/profiling"
"golang.org/x/sys/unix"
@@ -86,14 +86,14 @@ func (r *Runner) Init(task *base.ProfilingTask, processes []api.ProcessInterface
if len(processes) != 1 {
return fmt.Errorf("the processes count must be 1, current is: %d", len(processes))
}
- process := processes[0]
- r.pid = process.Pid()
+ curProcess := processes[0]
+ r.pid = curProcess.Pid()
// process profiling stat
- if r.processProfiling = process.ProfilingStat(); r.processProfiling == nil {
+ if r.processProfiling = curProcess.ProfilingStat(); r.processProfiling == nil {
return fmt.Errorf("this process could not be profiling")
}
// kernel profiling stat
- kernelProfiling, err := tools.KernelFileProfilingStat()
+ kernelProfiling, err := process.KernelFileProfilingStat()
if err != nil {
log.Warnf("could not analyze kernel profiling stats: %v", err)
}
diff --git a/pkg/tools/btf/linker.go b/pkg/tools/btf/linker.go
index 8c80726..d08242a 100644
--- a/pkg/tools/btf/linker.go
+++ b/pkg/tools/btf/linker.go
@@ -28,8 +28,8 @@ import (
"golang.org/x/arch/x86/x86asm"
- "github.com/apache/skywalking-rover/pkg/tools"
"github.com/apache/skywalking-rover/pkg/tools/elf"
+ "github.com/apache/skywalking-rover/pkg/tools/process"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/link"
@@ -46,7 +46,7 @@ type RingBufferReader func(data interface{})
var syscallPrefix string
func init() {
- stat, err := tools.KernelFileProfilingStat()
+ stat, err := process.KernelFileProfilingStat()
if err != nil {
syscallPrefix = defaultSymbolPrefix
return
diff --git a/pkg/tools/process.go b/pkg/tools/process/process.go
similarity index 94%
rename from pkg/tools/process.go
rename to pkg/tools/process/process.go
index 9539093..1186b8e 100644
--- a/pkg/tools/process.go
+++ b/pkg/tools/process/process.go
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package process
import (
"bufio"
@@ -61,8 +61,8 @@ func KernelFileProfilingStat() (*profiling.Info, error) {
return kernelFinder.Analyze(profiling.KernelSymbolFilePath)
}
-// ProcessProfilingStat is validating the exe file could be profiling and get info
-func ProcessProfilingStat(pid int32, exePath string) (*profiling.Info, error) {
+// ProfilingStat is validating the exe file could be profiling and get info
+func ProfilingStat(pid int32, exePath string) (*profiling.Info, error) {
stat, err := os.Stat(exePath)
if err != nil {
return nil, fmt.Errorf("check file error: %v", err)
@@ -83,8 +83,8 @@ func ProcessProfilingStat(pid int32, exePath string) (*profiling.Info, error) {
return analyzeProfilingInfo(context, pid)
}
-// ProcessModules Read the profiling info of the process, without the symbol check
-func ProcessModules(pid int32) ([]*profiling.Module, error) {
+// Modules Read the profiling info of the process, without the symbol check
+func Modules(pid int32) ([]*profiling.Module, error) {
context := newAnalyzeContext()
info, err := analyzeProfilingInfo(context, pid)
if err != nil {
diff --git a/pkg/tools/ssl/envoy.go b/pkg/tools/ssl/envoy.go
new file mode 100644
index 0000000..7ccc298
--- /dev/null
+++ b/pkg/tools/ssl/envoy.go
@@ -0,0 +1,75 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package ssl
+
+import (
+ "fmt"
+
+ "github.com/cilium/ebpf"
+)
+
+type EnvoySymbolAddress struct {
+ IsServerOffset uint64
+}
+
+func (r *Register) Envoy(envoySymbolAddrMap *ebpf.Map, sslWrite, sslWriteRet, sslRead, sslReadRet *ebpf.Program) {
+ r.addHandler("Envoy", func() (bool, error) {
+ moduleName := "/envoy"
+ processModules, err := r.findModules(moduleName)
+ if err != nil {
+ return false, err
+ }
+ envoyModule := processModules[moduleName]
+ if envoyModule == nil {
+ return false, nil
+ }
+ var readSymbol, writeSymbol bool
+ for _, sym := range envoyModule.Symbols {
+ if sym.Name == "SSL_read" {
+ readSymbol = true
+ } else if sym.Name == "SSL_write" {
+ writeSymbol = true
+ }
+ }
+ if !readSymbol || !writeSymbol {
+ log.Debugf("found the envoy process, but the ssl read or write symbol not exists, so ignore. read: %t, write: %t",
+ readSymbol, writeSymbol)
+ return false, nil
+ }
+
+ if envoySymbolAddrMap != nil {
+ addr := &EnvoySymbolAddress{
+ // for now the server field have fixed position
+ // https://github.com/google/boringssl/blob/master/ssl/internal.h#L3734-L3812
+ IsServerOffset: 164,
+ }
+
+ if err := envoySymbolAddrMap.Put(uint32(r.pid), addr); err != nil {
+ return false, fmt.Errorf("setting the envoy symbol offsets failure, pid: %d, error: %v", r.pid, err)
+ }
+ }
+
+ envoy := r.linker.OpenUProbeExeFile(envoyModule.Path)
+ envoy.AddLink("SSL_write", sslWrite, sslWriteRet)
+ envoy.AddLink("SSL_read", sslRead, sslReadRet)
+ if e := r.linker.HasError(); e != nil {
+ return false, e
+ }
+ return true, nil
+ })
+}
diff --git a/pkg/tools/ssl/gotls.go b/pkg/tools/ssl/gotls.go
new file mode 100644
index 0000000..2a88498
--- /dev/null
+++ b/pkg/tools/ssl/gotls.go
@@ -0,0 +1,258 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package ssl
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "regexp"
+
+ "github.com/apache/skywalking-rover/pkg/tools/elf"
+ "github.com/apache/skywalking-rover/pkg/tools/host"
+ "github.com/apache/skywalking-rover/pkg/tools/profiling"
+ "github.com/apache/skywalking-rover/pkg/tools/version"
+
+ "github.com/cilium/ebpf"
+)
+
+var (
+ goVersionRegex = regexp.MustCompile(`^go(?P<Major>\d)\.(?P<Minor>\d+)`)
+
+ goTLSWriteSymbol = "crypto/tls.(*Conn).Write"
+ goTLSReadSymbol = "crypto/tls.(*Conn).Read"
+ goTLSGIDStatusSymbol = "runtime.casgstatus"
+ goTLSPollFDSymbol = "internal/poll.FD"
+ goTLSConnSymbol = "crypto/tls.Conn"
+ goTLSRuntimeG = "runtime.g"
+)
+
+type GoTLSArgsLocationType uint32
+
+const (
+ GoTLSArgsLocationTypeStack GoTLSArgsLocationType = 1
+ GoTLSArgsLocationTypeRegister GoTLSArgsLocationType = 2
+)
+
+type GoSymbolLocation struct {
+ Type GoTLSArgsLocationType
+ Offset uint32
+}
+
+type GoTLSSymbolAddress struct {
+ // net.Conn addresses
+ FDSysFDOffset uint64
+ TLSConnOffset uint64
+ GIDOffset uint64
+ TCPConnOffset uint64
+ IsClientOffset uint64
+
+ // casgstatus(goroutine status change) function relate locations
+ CasgStatusGPLoc GoSymbolLocation
+ CasgStatusNEWValLoc GoSymbolLocation
+
+ // write function relate locations
+ WriteConnectionLoc GoSymbolLocation
+ WriteBufferLoc GoSymbolLocation
+ WriteRet0Loc GoSymbolLocation
+ WriteRet1Loc GoSymbolLocation
+
+ // write function relate locations
+ ReadConnectionLoc GoSymbolLocation
+ ReadBufferLoc GoSymbolLocation
+ ReadRet0Loc GoSymbolLocation
+ ReadRet1Loc GoSymbolLocation
+}
+
+func (r *Register) GoTLS(symbolAddrMap *ebpf.Map, goIDChange, write, writeRet, read, readRet *ebpf.Program) {
+ r.addHandler("goTLS", func() (bool, error) {
+ buildVersionSymbol := r.searchSymbolInModules(r.modules, func(a, b string) bool {
+ return a == b
+ }, "runtime.buildVersion")
+ if buildVersionSymbol == nil {
+ return false, nil
+ }
+ pidExeFile := host.GetFileInHost(fmt.Sprintf("/proc/%d/exe", r.pid))
+ elfFile, err := elf.NewFile(pidExeFile)
+ if err != nil {
+ return false, fmt.Errorf("read executable file error: %v", err)
+ }
+ defer elfFile.Close()
+
+ v, err := r.getGoVersion(elfFile, buildVersionSymbol)
+ if err != nil {
+ return false, err
+ }
+
+ offsets, err := r.generateGOTLSSymbolOffsets(r, elfFile, v)
+ if err != nil {
+ return false, err
+ }
+ if offsets == nil {
+ return false, nil
+ }
+
+ // setting the locations
+ if err := symbolAddrMap.Put(uint32(r.pid), offsets); err != nil {
+ return false, fmt.Errorf("setting the Go TLS argument location failure, pid: %d, error: %v", r.pid, err)
+ }
+
+ exeFile := r.linker.OpenUProbeExeFile(pidExeFile)
+ exeFile.AddLinkWithType("runtime.casgstatus", true, goIDChange)
+ exeFile.AddGoLink(goTLSWriteSymbol, write, writeRet, elfFile)
+ exeFile.AddGoLink(goTLSReadSymbol, read, readRet, elfFile)
+ if e := r.linker.HasError(); e != nil {
+ return false, e
+ }
+
+ return true, nil
+ })
+}
+
+func (r *Register) getGoVersion(elfFile *elf.File, versionSymbol *profiling.Symbol) (*version.Version, error) {
+ buffer, err := elfFile.ReadSymbolData(".data", versionSymbol.Location, versionSymbol.Size)
+ if err != nil {
+ return nil, fmt.Errorf("reading go version struct info failure: %v", err)
+ }
+ var t = goStringInC{}
+ buf := bytes.NewReader(buffer)
+ err = binary.Read(buf, binary.LittleEndian, &t)
+ if err != nil {
+ return nil, fmt.Errorf("read the go structure failure: %v", err)
+ }
+ buffer, err = elfFile.ReadSymbolData(".data", t.Ptr, t.Size)
+ if err != nil {
+ return nil, fmt.Errorf("read the go version failure: %v", err)
+ }
+
+ // parse versions
+ submatch := goVersionRegex.FindStringSubmatch(string(buffer))
+ if len(submatch) != 3 {
+ return nil, fmt.Errorf("the go version is failure to identify, version: %s", string(buffer))
+ }
+ return version.Read(submatch[1], submatch[2], "")
+}
+
+type goStringInC struct {
+ Ptr uint64
+ Size uint64
+}
+
+func (r *Register) generateGOTLSSymbolOffsets(register *Register, elfFile *elf.File, v *version.Version) (*GoTLSSymbolAddress, error) {
+ reader, err := elfFile.NewDwarfReader(
+ goTLSReadSymbol, goTLSWriteSymbol, goTLSGIDStatusSymbol,
+ goTLSPollFDSymbol, goTLSConnSymbol, goTLSRuntimeG)
+ if err != nil {
+ return nil, err
+ }
+
+ symbolAddresses := &GoTLSSymbolAddress{}
+
+ sym := register.SearchSymbol(func(a, b string) bool {
+ return a == b
+ }, "go.itab.*net.TCPConn,net.Conn")
+ if sym == nil {
+ log.Warnf("could not found the tcp connection symbol: go.itab.*net.TCPConn,net.Conn")
+ return nil, nil
+ }
+ symbolAddresses.TCPConnOffset = sym.Location
+
+ readFunction := reader.GetFunction(goTLSReadSymbol)
+ if readFunction == nil {
+ log.Warnf("could not found the go tls read symbol: %s", goTLSReadSymbol)
+ return nil, nil
+ }
+ writeFunction := reader.GetFunction(goTLSWriteSymbol)
+ if writeFunction == nil {
+ log.Warnf("could not found the go tls write symbol: %s", goTLSWriteSymbol)
+ return nil, nil
+ }
+ gidStatusFunction := reader.GetFunction(goTLSGIDStatusSymbol)
+ if gidStatusFunction == nil {
+ log.Warnf("could not found the goid status change symbol: %s", goTLSGIDStatusSymbol)
+ return nil, nil
+ }
+
+ var retValArg0, retValArg1 = "~r1", "~r2"
+ if v.Minor >= 18 {
+ retValArg0, retValArg1 = "~r0", "~r1"
+ }
+
+ // build the symbols
+ var assignError error
+ // offset
+ assignError = r.assignGoTLSStructureOffset(assignError, reader, goTLSPollFDSymbol, "Sysfd", &symbolAddresses.FDSysFDOffset)
+ assignError = r.assignGoTLSStructureOffset(assignError, reader, goTLSConnSymbol, "conn", &symbolAddresses.TLSConnOffset)
+ assignError = r.assignGoTLSStructureOffset(assignError, reader, goTLSRuntimeG, "goid", &symbolAddresses.GIDOffset)
+ assignError = r.assignGoTLSStructureOffset(assignError, reader, goTLSConnSymbol, "isClient", &symbolAddresses.IsClientOffset)
+
+ // gid status change
+ assignError = r.assignGoTLSArgsLocation(assignError, gidStatusFunction, "gp", &symbolAddresses.CasgStatusGPLoc)
+ assignError = r.assignGoTLSArgsLocation(assignError, gidStatusFunction, "newval", &symbolAddresses.CasgStatusNEWValLoc)
+
+ // write
+ assignError = r.assignGoTLSArgsLocation(assignError, writeFunction, "c", &symbolAddresses.WriteConnectionLoc)
+ assignError = r.assignGoTLSArgsLocation(assignError, writeFunction, "b", &symbolAddresses.WriteBufferLoc)
+ assignError = r.assignGoTLSArgsLocation(assignError, writeFunction, retValArg0, &symbolAddresses.WriteRet0Loc)
+ assignError = r.assignGoTLSArgsLocation(assignError, writeFunction, retValArg1, &symbolAddresses.WriteRet1Loc)
+ // read
+ assignError = r.assignGoTLSArgsLocation(assignError, readFunction, "c", &symbolAddresses.ReadConnectionLoc)
+ assignError = r.assignGoTLSArgsLocation(assignError, readFunction, "b", &symbolAddresses.ReadBufferLoc)
+ assignError = r.assignGoTLSArgsLocation(assignError, readFunction, retValArg0, &symbolAddresses.ReadRet0Loc)
+ assignError = r.assignGoTLSArgsLocation(assignError, readFunction, retValArg1, &symbolAddresses.ReadRet1Loc)
+
+ return symbolAddresses, assignError
+}
+
+func (r *Register) assignGoTLSStructureOffset(err error, reader *elf.DwarfReader, structName, fieldName string, dest *uint64) error {
+ if err != nil {
+ return err
+ }
+ structure := reader.GetStructure(structName)
+ if structure == nil {
+ return fmt.Errorf("the structure is not found, name: %s", structName)
+ }
+ field := structure.GetField(fieldName)
+ if field == nil {
+ return fmt.Errorf("the field is not found in structure, structure name: %s, field name: %s", structName, fieldName)
+ }
+ *dest = uint64(field.Offset)
+ return nil
+}
+
+func (r *Register) assignGoTLSArgsLocation(err error, function *elf.FunctionInfo, argName string, dest *GoSymbolLocation) error {
+ if err != nil {
+ return err
+ }
+ var kSPOffset uint32 = 8
+ args := function.Args(argName)
+ if args == nil {
+ return fmt.Errorf("the args is not found, function: %s, args name: %s", function.Name(), argName)
+ }
+ if args.Location.Type == elf.ArgLocationTypeStack {
+ dest.Type = GoTLSArgsLocationTypeStack
+ dest.Offset = uint32(args.Location.Offset) + kSPOffset
+ } else if args.Location.Type == elf.ArgLocationTypeRegister {
+ dest.Type = GoTLSArgsLocationTypeRegister
+ dest.Offset = uint32(args.Location.Offset)
+ } else {
+ return fmt.Errorf("the location type is not support, function: %s, args name: %s, type: %d",
+ function.Name(), argName, args.Location.Type)
+ }
+ return nil
+}
diff --git a/pkg/tools/ssl/node.go b/pkg/tools/ssl/node.go
new file mode 100644
index 0000000..e0f2f99
--- /dev/null
+++ b/pkg/tools/ssl/node.go
@@ -0,0 +1,211 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package ssl
+
+import (
+ "fmt"
+ "os/exec"
+ "regexp"
+ "strings"
+
+ "github.com/apache/skywalking-rover/pkg/tools/btf"
+ "github.com/apache/skywalking-rover/pkg/tools/profiling"
+ "github.com/apache/skywalking-rover/pkg/tools/version"
+
+ "github.com/cilium/ebpf"
+)
+
+var (
+ nodeVersionRegex = regexp.MustCompile(`^node\.js/v(?P<Major>\d+)\.(?P<Minor>\d+)\.(?P<Patch>\d+)$`)
+)
+
+type NodeTLSSymbolAddress struct {
+ TLSWrapStreamListenerOffset uint32
+ StreamListenerStreamOffset uint32
+ StreamBaseStreamResourceOffset uint32
+ LibuvStreamWrapStreamBaseOffset uint32
+ LibuvStreamWrapStreamOffset uint32
+ UVStreamSIOWatcherOffset uint32
+ UVIOSFDOffset uint32
+}
+
+func (r *Register) Node(sslSymbolOffsetsMap, nodeTLSSymbolOffsetsMap *ebpf.Map,
+ sslWrite, sslWriteRet, sslRead, sslReadRet,
+ sslNew, tlsWrap, tlsWrapRet *ebpf.Program) {
+ r.addHandler("Node", func() (bool, error) {
+ libSSLModule, nodeModule, openSSLAttach, err := r.findNodeTLSModules()
+ if err != nil {
+ return false, err
+ }
+ if libSSLModule == nil || nodeModule == nil {
+ return false, nil
+ }
+ v, err := r.getNodeVersion(nodeModule.Path)
+ if err != nil {
+ return false, err
+ }
+ log.Debugf("read the nodejs version, pid: %d, version: %s", r.pid, v)
+ // openSSL symbol offsets
+ if sslSymbolOffsetsMap != nil {
+ config, err := r.buildOpenSSLSymAddrConfig(libSSLModule.Path)
+ if err != nil {
+ return false, err
+ }
+ if err := sslSymbolOffsetsMap.Put(uint32(r.pid), config); err != nil {
+ return false, err
+ }
+ }
+ if nodeTLSSymbolOffsetsMap != nil {
+ config, err := r.findNodeTLSAddrConfig(v)
+ if err != nil {
+ return false, err
+ }
+ // setting the locations
+ if err := nodeTLSSymbolOffsetsMap.Put(uint32(r.pid), config); err != nil {
+ return false, fmt.Errorf("setting the node TLS location failure, pid: %d, error: %v", r.pid, err)
+ }
+ }
+ libSSLLinker := r.linker.OpenUProbeExeFile(libSSLModule.Path)
+ if openSSLAttach {
+ libSSLLinker.AddLink("SSL_write", sslWrite, sslWriteRet)
+ libSSLLinker.AddLink("SSL_read", sslRead, sslReadRet)
+ }
+ if e := r.nodeTLSRegisterProbes(v, libSSLLinker, nodeModule, sslNew, tlsWrap, tlsWrapRet); e != nil {
+ return false, e
+ }
+ if e := r.linker.HasError(); e != nil {
+ return false, e
+ }
+ return true, nil
+ })
+}
+
+func (r *Register) getNodeVersion(p string) (*version.Version, error) {
+ result, err := exec.Command("strings", p).Output()
+ if err != nil {
+ return nil, err
+ }
+ for _, d := range strings.Split(string(result), "\n") {
+ versionInfo := nodeVersionRegex.FindStringSubmatch(strings.TrimSpace(d))
+ if len(versionInfo) != 4 {
+ continue
+ }
+ return version.Read(versionInfo[1], versionInfo[2], versionInfo[3])
+ }
+
+ return nil, fmt.Errorf("nodejs version is not found")
+}
+
+var nodeTLSAddrWithVersions = []struct {
+ v *version.Version
+ conf *NodeTLSSymbolAddress
+}{
+ {version.Build(10, 19, 0), &NodeTLSSymbolAddress{0x0130, 0x08, 0x00, 0x50, 0x90, 0x88, 0x30}},
+ {version.Build(12, 3, 1), &NodeTLSSymbolAddress{0x0130, 0x08, 0x00, 0x50, 0x90, 0x88, 0x30}},
+ {version.Build(12, 16, 2), &NodeTLSSymbolAddress{0x0138, 0x08, 0x00, 0x58, 0x98, 0x88, 0x30}},
+ {version.Build(13, 0, 0), &NodeTLSSymbolAddress{0x0130, 0x08, 0x00, 0x50, 0x90, 0x88, 0x30}},
+ {version.Build(13, 2, 0), &NodeTLSSymbolAddress{0x0130, 0x08, 0x00, 0x58, 0x98, 0x88, 0x30}},
+ {version.Build(13, 10, 1), &NodeTLSSymbolAddress{0x0140, 0x08, 0x00, 0x60, 0xa0, 0x88, 0x30}},
+ {version.Build(14, 5, 0), &NodeTLSSymbolAddress{0x138, 0x08, 0x00, 0x58, 0x98, 0x88, 0x30}},
+ {version.Build(15, 0, 0), &NodeTLSSymbolAddress{0x78, 0x08, 0x00, 0x58, 0x98, 0x88, 0x30}},
+}
+
+var nodeTLSProbeWithVersions = []struct {
+ v *version.Version
+ f func(uprobe *btf.UProbeExeFile, register *Register, nodeModule *profiling.Module, tlsWrap, tlsWrapRet *ebpf.Program)
+}{
+ {version.Build(10, 19, 0), func(uprobe *btf.UProbeExeFile, register *Register, nodeModule *profiling.Module, tlsWrap, tlsWrapRet *ebpf.Program) {
+ uprobe.AddLinkWithSymbols(register.searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node7TLSWrapC2E"),
+ tlsWrap, tlsWrapRet)
+ uprobe.AddLinkWithSymbols(register.searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node7TLSWrap7ClearInE"),
+ tlsWrap, tlsWrapRet)
+ uprobe.AddLinkWithSymbols(register.searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node7TLSWrap8ClearOutE"),
+ tlsWrap, tlsWrapRet)
+ }},
+ {version.Build(15, 0, 0), func(uprobe *btf.UProbeExeFile, register *Register, nodeModule *profiling.Module, tlsWrap, tlsWrapRet *ebpf.Program) {
+ uprobe.AddLinkWithSymbols(register.searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node6crypto7TLSWrapC2E"),
+ tlsWrap, tlsWrapRet)
+ uprobe.AddLinkWithSymbols(register.searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node6crypto7TLSWrap7ClearInE"),
+ tlsWrap, tlsWrapRet)
+ uprobe.AddLinkWithSymbols(register.searchSymbolNames([]*profiling.Module{nodeModule}, strings.HasPrefix, "_ZN4node6crypto7TLSWrap8ClearOutE"),
+ tlsWrap, tlsWrapRet)
+ }},
+}
+
+func (r *Register) findNodeTLSAddrConfig(v *version.Version) (*NodeTLSSymbolAddress, error) {
+ var lastest *NodeTLSSymbolAddress
+ for _, c := range nodeTLSAddrWithVersions {
+ if v.GreaterOrEquals(c.v) {
+ lastest = c.conf
+ }
+ }
+ if lastest != nil {
+ return lastest, nil
+ }
+ return nil, fmt.Errorf("could not support version: %s", v)
+}
+
+func (r *Register) findNodeTLSModules() (libSSLModule, nodeModule *profiling.Module, openSSLAttach bool, err error) {
+ moduleName1, moduleName2, libsslName := "/nodejs", "/node", "libssl.so"
+ processModules, err := r.findModules(moduleName1, moduleName2, libsslName)
+ if err != nil {
+ return nil, nil, false, err
+ }
+ nodeModule = processModules[moduleName1]
+ libSSLModule = processModules[libsslName]
+ if nodeModule == nil {
+ nodeModule = processModules[moduleName2]
+ }
+ if nodeModule == nil {
+ return nil, nil, false, nil
+ }
+ if libSSLModule == nil {
+ if r.searchSymbolInModules([]*profiling.Module{nodeModule}, func(a, b string) bool {
+ return a == b
+ }, "SSL_read") == nil || r.searchSymbolInModules([]*profiling.Module{nodeModule}, func(a, b string) bool {
+ return a == b
+ }, "SSL_write") == nil {
+ return nil, nil, false, nil
+ }
+ libSSLModule = nodeModule
+ openSSLAttach = true
+ }
+ return
+}
+
+func (r *Register) nodeTLSRegisterProbes(v *version.Version, libSSLLinker *btf.UProbeExeFile, nodeModule *profiling.Module,
+ sslNew, tlsWrap, tlsWrapRet *ebpf.Program) error {
+ if sslNew != nil {
+ libSSLLinker.AddLinkWithType("SSL_new", false, sslNew)
+ }
+ if tlsWrap != nil && tlsWrapRet != nil {
+ var probeFunc func(uprobe *btf.UProbeExeFile, register *Register, nodeModule *profiling.Module, tlsWrap, tlsWrapRet *ebpf.Program)
+ for _, c := range nodeTLSProbeWithVersions {
+ if v.GreaterOrEquals(c.v) {
+ probeFunc = c.f
+ }
+ }
+ if probeFunc == nil {
+ return fmt.Errorf("the version is not support to attach TLSWrap relate probes: %v, pid: %d", v, r.pid)
+ }
+ file := r.linker.OpenUProbeExeFile(nodeModule.Path)
+ probeFunc(file, r, nodeModule, tlsWrap, tlsWrapRet)
+ }
+
+ return nil
+}
diff --git a/pkg/tools/ssl/openssl.go b/pkg/tools/ssl/openssl.go
new file mode 100644
index 0000000..87f1931
--- /dev/null
+++ b/pkg/tools/ssl/openssl.go
@@ -0,0 +1,141 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package ssl
+
+import (
+ "fmt"
+ "os/exec"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/cilium/ebpf"
+)
+
+var (
+ openSSLVersionRegex = regexp.MustCompile(`^OpenSSL\s+(?P<Major>\d)\.(?P<Minor>\d)\.(?P<Fix>\d+)\w?`)
+)
+
+type OpenSSLSymbolAddresses struct {
+ BIOReadOffset uint32
+ BIOWriteOffset uint32
+ FDOffset uint32
+ RoleOffset uint32
+}
+
+func (r *Register) OpenSSL(symbolAddrMap *ebpf.Map, sslWrite, sslWriteRet, sslRead, sslReadRet *ebpf.Program) {
+ r.addHandler("OpenSSL", func() (bool, error) {
+ var libcryptoName, libsslName = "libcrypto.so", "libssl.so"
+ var libcryptoPath, libsslPath string
+ modules, err := r.findModules(libcryptoName, libsslName)
+ if err != nil {
+ return false, err
+ }
+ if len(modules) == 0 {
+ return false, nil
+ }
+ if libcrypto := modules[libcryptoName]; libcrypto != nil {
+ libcryptoPath = libcrypto.Path
+ }
+ if libssl := modules[libsslName]; libssl != nil {
+ libsslPath = libssl.Path
+ }
+ if libcryptoPath == "" || libsslPath == "" {
+ return false, fmt.Errorf("the OpenSSL library not complete, libcrypto: %s, libssl: %s", libcryptoPath, libsslPath)
+ }
+
+ addresses, err := r.buildOpenSSLSymAddrConfig(libcryptoPath)
+ if err != nil {
+ return false, err
+ }
+
+ if err := symbolAddrMap.Put(uint32(r.pid), addresses); err != nil {
+ return false, err
+ }
+
+ libSSLLinker := r.linker.OpenUProbeExeFile(libsslPath)
+ libSSLLinker.AddLink("SSL_write", sslWrite, sslWriteRet)
+ libSSLLinker.AddLink("SSL_read", sslRead, sslReadRet)
+ if err := r.linker.HasError(); err != nil {
+ return false, err
+ }
+ return true, nil
+ })
+}
+
+func (r *Register) buildOpenSSLSymAddrConfig(libcryptoPath string) (*OpenSSLSymbolAddresses, error) {
+ // using "strings" command to query the symbol in the libcrypto library
+ result, err := exec.Command("strings", libcryptoPath).Output()
+ if err != nil {
+ return nil, err
+ }
+ for _, p := range strings.Split(string(result), "\n") {
+ submatch := openSSLVersionRegex.FindStringSubmatch(p)
+ if len(submatch) != 4 {
+ continue
+ }
+ major := submatch[1]
+ minor := submatch[2]
+ fix := submatch[3]
+
+ log.Debugf("found the libcrypto.so version: %s.%s.%s", major, minor, fix)
+ conf := &OpenSSLSymbolAddresses{}
+
+ // must be number, already validate in the regex
+ majorVal, _ := strconv.Atoi(major)
+ minorVal, _ := strconv.Atoi(minor)
+ fixVal, _ := strconv.Atoi(fix)
+
+ // max support version is 3.0.x
+ if majorVal > 3 || (majorVal == 3 && minorVal > 0) {
+ return nil, fmt.Errorf("the version of the libcrypto is not support: %s.%s.%s", major, minor, fix)
+ }
+
+ // bio offset
+ // https://github.com/openssl/openssl/blob/OpenSSL_1_0_0-stable/ssl/ssl.h#L1093-L1111
+ // https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/ssl/ssl_local.h#L1068-L1083
+ // https://github.com/openssl/openssl/blob/openssl-3.0.7/ssl/ssl_local.h#L1212-L1227
+ conf.BIOReadOffset = 16
+ conf.BIOWriteOffset = 24
+ // fd offset
+ if majorVal == 3 && minorVal == 0 {
+ // 3.0.x
+ // https://github.com/openssl/openssl/blob/openssl-3.0.7/crypto/bio/bio_local.h#L115-L128
+ // OPENSSL_NO_DEPRECATED_3_0 is not defined by default unless the user pass the specific build option
+ conf.FDOffset = 56
+ // https://github.com/openssl/openssl/blob/openssl-3.0.7/ssl/ssl_local.h#L1212-L1245
+ conf.RoleOffset = 56
+ } else if (minorVal == 0) || (minorVal == 1 && fixVal == 0) {
+ // 1.0.x || 1.1.0
+ // https://github.com/openssl/openssl/blob/OpenSSL_1_0_0-stable/crypto/bio/bio.h#L297-L306
+ conf.FDOffset = 40
+ // https://github.com/openssl/openssl/blob/OpenSSL_1_0_0-stable/ssl/ssl.h#L1093-L1138
+ conf.RoleOffset = 72
+ } else {
+ // 1.1.1
+ // https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/crypto/bio/bio_local.h#L115-L125
+ conf.FDOffset = 48
+ // https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/ssl/ssl_local.h#L1068-L1101
+ conf.RoleOffset = 56
+ }
+ log.Debugf("the lobcrypto.so library symbol verson config, version: %s.%s.%s, bio offset: %d",
+ major, minor, fix, conf.FDOffset)
+ return conf, nil
+ }
+ return nil, fmt.Errorf("could not fount the version of the libcrypto.so")
+}
diff --git a/pkg/profiling/task/network/ssl_test.go b/pkg/tools/ssl/openssl_test.go
similarity index 76%
rename from pkg/profiling/task/network/ssl_test.go
rename to pkg/tools/ssl/openssl_test.go
index 1ed387d..cb0bb7c 100644
--- a/pkg/profiling/task/network/ssl_test.go
+++ b/pkg/tools/ssl/openssl_test.go
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-package network
+package ssl
import (
"os/exec"
@@ -29,6 +29,7 @@ func TestBuildSSLSymAddrConfig(t *testing.T) {
mockOutput := func(out string) *exec.Cmd {
return exec.Command("echo", out)
}
+ register := NewSSLRegister(0, nil)
result := `%s:%d: OpenSSL internal error: %s
OpenSSL 1.0.2o 31 Mar 2020
@@ -38,7 +39,7 @@ OpenSSL X9.42 DH method`
patches.Reset()
})
- conf, err := buildSSLSymAddrConfig("/test")
+ conf, err := register.buildOpenSSLSymAddrConfig("/test")
assert.Nil(t, err)
assert.Equal(t, uint32(16), conf.BIOReadOffset)
assert.Equal(t, uint32(24), conf.BIOWriteOffset)
@@ -49,7 +50,17 @@ OpenSSL X9.42 DH method`
OpenSSL 1.1.1f 31 Mar 2020
OpenSSL X9.42 DH method`
patches = gomonkey.ApplyFuncReturn(exec.Command, mockOutput(result))
- conf, err = buildSSLSymAddrConfig("/test")
+ conf, err = register.buildOpenSSLSymAddrConfig("/test")
+ assert.Nil(t, err)
+ assert.Equal(t, uint32(16), conf.BIOReadOffset)
+ assert.Equal(t, uint32(24), conf.BIOWriteOffset)
+ assert.Equal(t, uint32(48), conf.FDOffset)
+
+ // should same with 1.1.1, which from the NodeJS build-in version of OpenSSL
+ patches.Reset()
+ result = `OpenSSL 1.1.1q+quic 5 Jul 2022`
+ patches = gomonkey.ApplyFuncReturn(exec.Command, mockOutput(result))
+ conf, err = register.buildOpenSSLSymAddrConfig("/test")
assert.Nil(t, err)
assert.Equal(t, uint32(16), conf.BIOReadOffset)
assert.Equal(t, uint32(24), conf.BIOWriteOffset)
@@ -60,7 +71,7 @@ OpenSSL X9.42 DH method`
OpenSSL 3.0.3 3 May 2022
OpenSSL RSA method`
patches = gomonkey.ApplyFuncReturn(exec.Command, mockOutput(result))
- conf, err = buildSSLSymAddrConfig("/test")
+ conf, err = register.buildOpenSSLSymAddrConfig("/test")
assert.Nil(t, err)
assert.Equal(t, uint32(16), conf.BIOReadOffset)
assert.Equal(t, uint32(24), conf.BIOWriteOffset)
diff --git a/pkg/tools/ssl/ssl.go b/pkg/tools/ssl/ssl.go
new file mode 100644
index 0000000..4830821
--- /dev/null
+++ b/pkg/tools/ssl/ssl.go
@@ -0,0 +1,146 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package ssl
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/tools/btf"
+ "github.com/apache/skywalking-rover/pkg/tools/path"
+ "github.com/apache/skywalking-rover/pkg/tools/process"
+ "github.com/apache/skywalking-rover/pkg/tools/profiling"
+)
+
+type handler func() (bool, error)
+
+var log = logger.GetLogger("tools", "ssl")
+
+type Register struct {
+ pid int
+ linker *btf.Linker
+
+ handlers map[string]handler
+ modules []*profiling.Module
+}
+
+func NewSSLRegister(pid int, linker *btf.Linker) *Register {
+ return &Register{
+ pid: pid,
+ linker: linker,
+ handlers: make(map[string]handler),
+ }
+}
+
+func (r *Register) Execute() error {
+ modules, err := process.Modules(int32(r.pid))
+ if err != nil {
+ return fmt.Errorf("read process modules error: %v, error: %v", r.pid, err)
+ }
+ r.modules = modules
+
+ count := 0
+ for name, h := range r.handlers {
+ b, err := h()
+ if err != nil {
+ return err
+ }
+ if b {
+ count++
+ log.Debugf("success add register to process, pid: %d, name: %s", r.pid, name)
+ }
+ }
+ if count == 0 {
+ log.Debugf("cannot find any SSL register for process: %d", r.pid)
+ }
+ return nil
+}
+
+func (r *Register) addHandler(name string, h handler) {
+ r.handlers[name] = h
+}
+
+func (r *Register) findModules(names ...string) (map[string]*profiling.Module, error) {
+ result := make(map[string]*profiling.Module)
+ for _, mod := range r.modules {
+ for _, modName := range names {
+ if strings.Contains(mod.Name, modName) {
+ if !path.Exists(mod.Path) {
+ return nil, fmt.Errorf("the module path not exists, path: %s", mod.Path)
+ }
+ result[modName] = mod
+ }
+ }
+ }
+ return result, nil
+}
+
+func (r *Register) SearchSymbol(verify stringVerify, values ...string) *profiling.Symbol {
+ return r.searchSymbolInModules(r.modules, verify, values...)
+}
+
+func (r *Register) searchSymbolInModules(modules []*profiling.Module, verify stringVerify, values ...string) *profiling.Symbol {
+ list := r.searchSymbolListInModules(modules, verify, values...)
+ if len(list) > 0 {
+ return list[0]
+ }
+ return nil
+}
+
+func (r *Register) searchSymbolListInModules(modules []*profiling.Module, verify stringVerify, values ...string) []*profiling.Symbol {
+ var result []*profiling.Symbol
+ for _, mod := range modules {
+ for _, s := range mod.Symbols {
+ for _, validator := range values {
+ if verify(s.Name, validator) {
+ result = append(result, s)
+ }
+ }
+ }
+ }
+ return result
+}
+
+func (r *Register) searchSymbolNames(modules []*profiling.Module, verify stringVerify, values ...string) []string {
+ list := r.searchSymbolList(modules, verify, values...)
+ if len(list) > 0 {
+ result := make([]string, 0)
+ for _, i := range list {
+ result = append(result, i.Name)
+ }
+ return result
+ }
+ return nil
+}
+
+func (r *Register) searchSymbolList(modules []*profiling.Module, verify stringVerify, values ...string) []*profiling.Symbol {
+ var result []*profiling.Symbol
+ for _, mod := range modules {
+ for _, s := range mod.Symbols {
+ for _, validator := range values {
+ if verify(s.Name, validator) {
+ result = append(result, s)
+ }
+ }
+ }
+ }
+ return result
+}
+
+type stringVerify func(a, b string) bool