From 1f09b3959a15d1d339924170b95232bd9641f746 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 25 Feb 2014 13:24:11 -0600 Subject: [PATCH] Fix PR16616 by handling a NULL servername in sunrpc probes. * tapset/linux/rpc.stp (sunrpc.clnt.entry): Use __rpc_format_servername() to generate the 'servername' convenience variable. (__rpc_format_servername): New function. * tapset/linux/conversions.stp (kernel_string): Fix odd formatting of NULL value in the error message. --- tapset/linux/conversions.stp | 6 +- tapset/linux/rpc.stp | 110 +++++++++++++++++++++++++++-------- 2 files changed, 92 insertions(+), 24 deletions(-) diff --git a/tapset/linux/conversions.stp b/tapset/linux/conversions.stp index 3627f5932..2eb49ccb1 100644 --- a/tapset/linux/conversions.stp +++ b/tapset/linux/conversions.stp @@ -20,8 +20,12 @@ function kernel_string:string (addr:long) %{ /* pure */ kderef_string (destination, STAP_ARG_addr, MAXSTRINGLEN); if (0) { deref_fault: /* branched to from deref_string() */ + /* Why '%1p' below? On newer kernels, the snprintf() function pads + * out '(null)' to the same width as other pointers, which looks + * really odd in the following error message. Setting a format + * width of '1' fixes this. */ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), - "kernel string copy fault at 0x%p", (void *) (uintptr_t) STAP_ARG_addr); + "kernel string copy fault at %1p", (void *) (uintptr_t) STAP_ARG_addr); CONTEXT->last_error = CONTEXT->error_buffer; } %} diff --git a/tapset/linux/rpc.stp b/tapset/linux/rpc.stp index 10c9d7491..03e4b7559 100644 --- a/tapset/linux/rpc.stp +++ b/tapset/linux/rpc.stp @@ -165,7 +165,8 @@ probe _sunrpc.clnt.create_client.rpc_new_client_inline = args = $args %) __args = $args - servername = kernel_string($args->servername) + servername = __rpc_format_servername($args->servername, + $args->address) progname = kernel_string($args->program->name) prog = $args->prognumber vers = vers_from_prog($args->program, $args->version) @@ -179,7 +180,9 @@ probe _sunrpc.clnt.create_client.rpc_new_client_inline = args = __rpc_create_args[tid()] %) __args = __rpc_create_args[tid()] - servername = kernel_string(@cast(__args, "rpc_create_args", "kernel:sunrpc")->servername) + servername = __rpc_format_servername(@cast(__args, "rpc_create_args", "kernel:sunrpc")->servername, + @cast(__args, "rpc_create_args", "kernel:sunrpc")->address) + progname = kernel_string(@cast(__args, "rpc_create_args", "kernel:sunrpc")->program->name) prog = @cast(__args, "rpc_create_args", "kernel:sunrpc")->prognumber vers = vers_from_prog(@cast(__args, "rpc_create_args", "kernel:sunrpc")->program, @cast(__args, "rpc_create_args", "kernel:sunrpc")->version) @@ -197,7 +200,8 @@ probe _sunrpc.clnt.create_client.rpc_new_client = { if (@defined($args)) { # kernel > 2.6.18 - servername = kernel_string($args->servername) + servername = __rpc_format_servername($args->servername, + $args->address) progname = kernel_string($args->program->name) prog = $args->prognumber vers = vers_from_prog($args->program, $args->version) @@ -205,7 +209,7 @@ probe _sunrpc.clnt.create_client.rpc_new_client = } else { # kernel <= 2.6.18 - servername = kernel_string($servname) + servername = __rpc_format_servername($servname, &$xprt->addr) progname = kernel_string($program->name) prog = $program->number vers = vers_from_prog($program, $vers) @@ -220,7 +224,7 @@ probe _sunrpc.clnt.create_client.rpc_create_client = kernel.function("rpc_create_client") !, module("sunrpc").function("rpc_create_client") { - servername = kernel_string($servname) + servername = __rpc_format_servername($servname, &$xprt->addr) if (@defined($info)) { progname = kernel_string($info->name) prog = $info->number @@ -286,9 +290,14 @@ probe _sunrpc.clnt.create_client.return.rpc_create_client = probe sunrpc.clnt.clone_client = kernel.function("rpc_clone_client") !, module("sunrpc").function("rpc_clone_client") { - servername = kernel_string(@choose_defined($clnt->cl_server, - @cast(rcu_dereference($clnt->cl_xprt), - "struct rpc_xprt")->servername)) + if (@defined($clnt->cl_server)) + servername = __rpc_format_servername($clnt->cl_server, + &$clnt->cl_xprt->addr) + else { + __xprt = rcu_dereference($clnt->cl_xprt) + servername = __rpc_format_servername(@cast(__xprt, "rpc_xprt")->servername, + &@cast(__xprt, "rpc_xprt")->addr) + } progname = kernel_string(@choose_defined($clnt->cl_program->name, $clnt->cl_protname)) prog = prog_from_clnt($clnt) @@ -335,9 +344,14 @@ probe sunrpc.clnt.clone_client.return = probe sunrpc.clnt.shutdown_client = kernel.function("rpc_shutdown_client") !, module("sunrpc").function("rpc_shutdown_client") { - servername = kernel_string(@choose_defined($clnt->cl_server, - @cast(rcu_dereference($clnt->cl_xprt), - "struct rpc_xprt")->servername)) + if (@defined($clnt->cl_server)) + servername = __rpc_format_servername($clnt->cl_server, + &$clnt->cl_xprt->addr) + else { + __xprt = rcu_dereference($clnt->cl_xprt) + servername = __rpc_format_servername(@cast(__xprt, "rpc_xprt")->servername, + &@cast(__xprt, "rpc_xprt")->addr) + } progname = kernel_string(@choose_defined($clnt->cl_program->name, $clnt->cl_protname)) prog = prog_from_clnt($clnt) @@ -408,9 +422,14 @@ probe sunrpc.clnt.bind_new_program = kernel.function("rpc_bind_new_program") !, module("sunrpc").function("rpc_bind_new_program") { - servername = kernel_string(@choose_defined($old->cl_server, - @cast(rcu_dereference($old->cl_xprt), - "struct rpc_xprt")->servername)) + if (@defined($old->cl_server)) + servername = __rpc_format_servername($old->cl_server, + &$old->cl_xprt->addr) + else { + __xprt = rcu_dereference($old->cl_xprt) + servername = __rpc_format_servername(@cast(__xprt, "rpc_xprt")->servername, + &@cast(__xprt, "rpc_xprt")->addr) + } old_progname = kernel_string(@choose_defined($old->cl_program->name, $old->cl_protname)) old_prog = prog_from_clnt($old) @@ -450,9 +469,14 @@ probe sunrpc.clnt.bind_new_program.return = probe sunrpc.clnt.call_sync = kernel.function("rpc_call_sync") !, module("sunrpc").function("rpc_call_sync") { - servername = kernel_string(@choose_defined($clnt->cl_server, - @cast(rcu_dereference($clnt->cl_xprt), - "struct rpc_xprt")->servername)) + if (@defined($clnt->cl_server)) + servername = __rpc_format_servername($clnt->cl_server, + &$clnt->cl_xprt->addr) + else { + __xprt = rcu_dereference($clnt->cl_xprt) + servername = __rpc_format_servername(@cast(__xprt, "rpc_xprt")->servername, + &@cast(__xprt, "rpc_xprt")->addr) + } progname = kernel_string(@choose_defined($clnt->cl_program->name, $clnt->cl_protname)) prog = prog_from_clnt($clnt) @@ -498,9 +522,14 @@ probe sunrpc.clnt.call_sync.return = kernel.function("rpc_call_sync").return !, probe sunrpc.clnt.call_async = kernel.function("rpc_call_async") !, module("sunrpc").function("rpc_call_async") { - servername = kernel_string(@choose_defined($clnt->cl_server, - @cast(rcu_dereference($clnt->cl_xprt), - "struct rpc_xprt")->servername)) + if (@defined($clnt->cl_server)) + servername = __rpc_format_servername($clnt->cl_server, + &$clnt->cl_xprt->addr) + else { + __xprt = rcu_dereference($clnt->cl_xprt) + servername = __rpc_format_servername(@cast(__xprt, "rpc_xprt")->servername, + &@cast(__xprt, "rpc_xprt")->addr) + } progname = kernel_string(@choose_defined($clnt->cl_program->name, $clnt->cl_protname)) prog = prog_from_clnt($clnt) @@ -543,9 +572,14 @@ probe sunrpc.clnt.call_async.return = probe sunrpc.clnt.restart_call = kernel.function("rpc_restart_call") !, module("sunrpc").function("rpc_restart_call") { - servername = kernel_string(@choose_defined($task->tk_client->cl_server, - @cast(rcu_dereference($task->tk_client->cl_xprt), - "struct rpc_xprt")->servername)) + if (@defined($task->tk_client->cl_server)) + servername = __rpc_format_servername($task->tk_client->cl_server, + &$task->tk_client->cl_xprt->addr) + else { + __xprt = rcu_dereference($task->tk_client->cl_xprt) + servername = __rpc_format_servername(@cast(__xprt, "rpc_xprt")->servername, + &@cast(__xprt, "rpc_xprt")->addr) + } prog = prog_from_clnt($task->tk_client) xid = $task->tk_rqstp->rq_xid tk_pid = $task->tk_pid @@ -1190,3 +1224,33 @@ function addr_from_rqst_str:string(rqstp:long) @cast(addr, "sockaddr_in6")->sin6_port) } +%{ +#include +#include +#include +%} + +function __rpc_format_servername:string(servername:long, address:long) +{ + printf("__rpc_format_servername: %p\n", servername) + if (servername != 0) + return kernel_string(servername) + + // If 'servername' is NULL, create a string representation of + // the passed-in address. + // + // Note that 'address' is a generic 'struct sockaddr'. When + // you use it you have to cast it to the more specific + // structure based on the family type. + if (@cast(address, "sockaddr")->sa_family == %{ /* pure */ /* unprivileged */ AF_LOCAL %}) { + return kernel_string(@cast(address, "sockaddr_un")->sun_path) + } + else if (@cast(address, "sockaddr")->sa_family == %{ /* pure */ /* unprivileged */ AF_INET %}) { + return format_ipaddr(&@cast(address, "sockaddr_in")->sin_addr->s_addr, %{ /* pure */ /* unprivileged */ AF_INET %}) + } + else if (@cast(address, "sockaddr")->sa_family == %{ /* pure */ /* unprivileged */ AF_INET6 %}) { + return format_ipaddr(&@cast(address, "sockaddr_in6")->sin6_addr, + %{ /* pure */ /* unprivileged */ AF_INET6 %}) + } + return "*unknown address family*" +} -- 2.43.5