From: "Steven Rostedt (Google)" <rostedt@xxxxxxxxxxx> For security reasons, it is not safe to let a trace-cmd agent connect to *any* host. Have the -N option take a host name and only connect to that host. It still gives full control to any process on that host, but at least the agent is not fully open to *any* machine. Signed-off-by: Steven Rostedt (Google) <rostedt@xxxxxxxxxxx> --- tracecmd/include/trace-local.h | 7 ++++- tracecmd/trace-agent.c | 34 +++++++++++++++------ tracecmd/trace-listen.c | 55 ++++++++++++++++++++++++++++++++++ tracecmd/trace-record.c | 13 ++++++-- 4 files changed, 97 insertions(+), 12 deletions(-) diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index b3230529a45c..59771f586c37 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -122,7 +122,7 @@ void trace_convert(int argc, char **argv); int trace_record_agent(struct tracecmd_msg_handle *msg_handle, int cpus, int *fds, int argc, char **argv, bool use_fifos, - unsigned long long trace_id); + unsigned long long trace_id, const char *host); struct hook_list; @@ -267,6 +267,7 @@ struct buffer_instance { struct tracecmd_msg_handle *msg_handle; struct tracecmd_output *network_handle; + const char *host; struct pid_addr_maps *pid_maps; @@ -309,9 +310,13 @@ extern struct buffer_instance *first_instance; #define START_PORT_SEARCH 1500 #define MAX_PORT_SEARCH 6000 +struct sockaddr_storage; + int trace_net_make(int port, enum port_type type); int trace_net_search(int start_port, int *sfd, enum port_type type); int trace_net_print_connection(int fd); +bool trace_net_cmp_connection(struct sockaddr_storage *addr, const char *name); +bool trace_net_cmp_connection_fd(int fd, const char *name); struct buffer_instance *allocate_instance(const char *name); void add_instance(struct buffer_instance *instance, int cpu_count); diff --git a/tracecmd/trace-agent.c b/tracecmd/trace-agent.c index 59cecae770a6..f0723a6601a4 100644 --- a/tracecmd/trace-agent.c +++ b/tracecmd/trace-agent.c @@ -62,7 +62,8 @@ static void make_net(int nr, int *fds, unsigned int *ports) } } -static void make_sockets(int nr, int *fds, unsigned int *ports, bool network) +static void make_sockets(int nr, int *fds, unsigned int *ports, + const char * network) { if (network) return make_net(nr, fds, ports); @@ -109,7 +110,7 @@ static char *get_clock(int argc, char **argv) return NULL; } -static void trace_print_connection(int fd, bool network) +static void trace_print_connection(int fd, const char *network) { int ret; @@ -121,7 +122,7 @@ static void trace_print_connection(int fd, bool network) tracecmd_debug("Could not print connection fd:%d\n", fd); } -static void agent_handle(int sd, int nr_cpus, int page_size, bool network) +static void agent_handle(int sd, int nr_cpus, int page_size, const char *network) { struct tracecmd_tsync_protos *tsync_protos = NULL; struct tracecmd_time_sync *tsync = NULL; @@ -203,7 +204,7 @@ static void agent_handle(int sd, int nr_cpus, int page_size, bool network) die("Failed to send trace response"); trace_record_agent(msg_handle, nr_cpus, fds, argc, argv, - use_fifos, trace_id); + use_fifos, trace_id, network); if (tsync) { tracecmd_tsync_with_host_stop(tsync); @@ -248,14 +249,23 @@ static pid_t do_fork() return fork(); } -static void agent_serve(unsigned int port, bool do_daemon, bool network) +static void agent_serve(unsigned int port, bool do_daemon, const char *network) { + struct sockaddr_storage net_addr; + struct sockaddr *addr = NULL; + socklen_t *addr_len_p = NULL; + socklen_t addr_len = sizeof(net_addr); int sd, cd, nr_cpus; unsigned int cid; pid_t pid; signal(SIGCHLD, handle_sigchld); + if (network) { + addr = (struct sockaddr *)&net_addr; + addr_len_p = &addr_len; + } + nr_cpus = tracecmd_count_cpus(); page_size = getpagesize(); @@ -279,7 +289,7 @@ static void agent_serve(unsigned int port, bool do_daemon, bool network) die("daemon"); for (;;) { - cd = accept(sd, NULL, NULL); + cd = accept(sd, addr, addr_len_p); if (cd < 0) { if (errno == EINTR) continue; @@ -288,6 +298,12 @@ static void agent_serve(unsigned int port, bool do_daemon, bool network) if (tracecmd_get_debug()) trace_print_connection(cd, network); + if (network && !trace_net_cmp_connection(&net_addr, network)) { + dprint("Client does not match '%s'\n", network); + close(cd); + continue; + } + if (handler_pid) goto busy; @@ -314,7 +330,7 @@ void trace_agent(int argc, char **argv) { bool do_daemon = false; unsigned int port = TRACE_AGENT_DEFAULT_PORT; - bool network = false; + const char *network = NULL; if (argc < 2) usage(argv); @@ -332,7 +348,7 @@ void trace_agent(int argc, char **argv) {NULL, 0, NULL, 0} }; - c = getopt_long(argc-1, argv+1, "+hp:DN", + c = getopt_long(argc-1, argv+1, "+hp:DN:", long_options, &option_index); if (c == -1) break; @@ -341,7 +357,7 @@ void trace_agent(int argc, char **argv) usage(argv); break; case 'N': - network = true; + network = optarg; break; case 'p': port = atoi(optarg); diff --git a/tracecmd/trace-listen.c b/tracecmd/trace-listen.c index b7be761d032e..86d2b9e9deb2 100644 --- a/tracecmd/trace-listen.c +++ b/tracecmd/trace-listen.c @@ -756,6 +756,61 @@ static int do_fork(int cfd) return 0; } +bool trace_net_cmp_connection(struct sockaddr_storage *addr, const char *name) +{ + char host[NI_MAXHOST], nhost[NI_MAXHOST]; + char service[NI_MAXSERV]; + socklen_t addr_len = sizeof(*addr); + struct addrinfo *result, *rp; + struct addrinfo hints; + bool found = false; + int s; + + if (getnameinfo((struct sockaddr *)addr, addr_len, + host, NI_MAXHOST, + service, NI_MAXSERV, NI_NUMERICSERV)) + return -1; + + if (strcmp(host, name) == 0) + return true; + + /* Check other IPs that name could be for */ + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + /* Check other IPs that name could be for */ + s = getaddrinfo(name, NULL, &hints, &result); + if (s != 0) + return false; + + for (rp = result; rp != NULL; rp = rp->ai_next) { + if (getnameinfo(rp->ai_addr, rp->ai_addrlen, + nhost, NI_MAXHOST, + service, NI_MAXSERV, NI_NUMERICSERV)) + continue; + if (strcmp(host, nhost) == 0) { + found = 1; + break; + } + } + + freeaddrinfo(result); + return found; +} + +bool trace_net_cmp_connection_fd(int fd, const char *name) +{ + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + + if (getpeername(fd, (struct sockaddr *)&addr, &addr_len)) + return false; + + return trace_net_cmp_connection(&addr, name); +}; + int trace_net_print_connection(int fd) { char host[NI_MAXHOST], service[NI_MAXSERV]; diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index 9c930920c89e..27c4e7ba6f3f 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -3426,8 +3426,16 @@ static int create_recorder(struct buffer_instance *instance, int cpu, if (is_agent(instance)) { if (instance->use_fifos) fd = instance->fds[cpu]; - else + else { + again: fd = do_accept(instance->fds[cpu]); + if (instance->host && + !trace_net_cmp_connection_fd(fd, instance->host)) { + dprint("Client does not match '%s' for cpu:%d\n", + instance->host, cpu); + goto again; + } + } } else { fd = connect_port(host, instance->client_ports[cpu], instance->port_type); @@ -7275,7 +7283,7 @@ int trace_record_agent(struct tracecmd_msg_handle *msg_handle, int cpus, int *fds, int argc, char **argv, bool use_fifos, - unsigned long long trace_id) + unsigned long long trace_id, const char *host) { struct common_record_context ctx; char **argv_plus; @@ -7304,6 +7312,7 @@ int trace_record_agent(struct tracecmd_msg_handle *msg_handle, ctx.instance->use_fifos = use_fifos; ctx.instance->flags |= BUFFER_FL_AGENT; ctx.instance->msg_handle = msg_handle; + ctx.instance->host = host; msg_handle->version = V3_PROTOCOL; top_instance.trace_id = trace_id; record_trace(argc, argv, &ctx); -- 2.35.1