hsmd: wire up dev_memleak.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2018-11-22 12:47:29 +10:30
parent 1430036684
commit 6da379631f
3 changed files with 78 additions and 4 deletions

View File

@ -176,6 +176,12 @@ hsm_get_per_commitment_point_reply,118
hsm_get_per_commitment_point_reply,,per_commitment_point,struct pubkey
hsm_get_per_commitment_point_reply,,old_commitment_secret,?struct secret
# master -> hsmd: do you have a memleak?
hsm_dev_memleak,33
hsm_dev_memleak_reply,133
hsm_dev_memleak_reply,,leak,bool
# channeld asks to check if claimed future commitment_secret is correct.
hsm_check_future_secret,22
hsm_check_future_secret,,n,u64

1 # Clients should not give a bad request but not the HSM's decision to crash.
176
177
178
179
180
181
182
183
184
185
186
187

View File

@ -30,6 +30,7 @@
#include <common/funding_tx.h>
#include <common/hash_u5.h>
#include <common/key_derive.h>
#include <common/memleak.h>
#include <common/status.h>
#include <common/subdaemon.h>
#include <common/type_to_string.h>
@ -101,7 +102,8 @@ static UINTMAP(struct client *) clients;
static struct client *dbid_zero_clients[3];
static size_t num_dbid_zero_clients;
/*~ We need this deep inside bad_req_fmt, so we make it a global. */
/*~ We need this deep inside bad_req_fmt, and for memleak, so we make it a
* global. */
static struct daemon_conn *status_conn;
/* This is used for various assertions and error cases. */
@ -1537,6 +1539,30 @@ static struct io_plan *handle_sign_node_announcement(struct io_conn *conn,
return req_reply(conn, c, take(reply));
}
#if DEVELOPER
static struct io_plan *handle_memleak(struct io_conn *conn,
struct client *c,
const u8 *msg_in)
{
struct htable *memtable;
bool found_leak;
u8 *reply;
memtable = memleak_enter_allocations(tmpctx, msg_in, msg_in);
/* Now delete clients and anything they point to. */
memleak_remove_referenced(memtable, c);
memleak_scan_region(memtable,
dbid_zero_clients, sizeof(dbid_zero_clients));
memleak_remove_uintmap(memtable, &clients);
memleak_scan_region(memtable, status_conn, tal_bytelen(status_conn));
found_leak = dump_memleak(memtable);
reply = towire_hsm_dev_memleak_reply(NULL, found_leak);
return req_reply(conn, c, take(reply));
}
#endif /* DEVELOPER */
/*~ This routine checks that a client is allowed to call the handler. */
static bool check_client_capabilities(struct client *client,
enum hsm_wire_type t)
@ -1588,6 +1614,7 @@ static bool check_client_capabilities(struct client *client,
case WIRE_HSM_SIGN_INVOICE:
case WIRE_HSM_SIGN_COMMITMENT_TX:
case WIRE_HSM_GET_CHANNEL_BASEPOINTS:
case WIRE_HSM_DEV_MEMLEAK:
return (client->capabilities & HSM_CAP_MASTER) != 0;
/*~ These are messages sent by the HSM so we should never receive them.
@ -1608,6 +1635,7 @@ static bool check_client_capabilities(struct client *client,
case WIRE_HSM_GET_PER_COMMITMENT_POINT_REPLY:
case WIRE_HSM_CHECK_FUTURE_SECRET_REPLY:
case WIRE_HSM_GET_CHANNEL_BASEPOINTS_REPLY:
case WIRE_HSM_DEV_MEMLEAK_REPLY:
break;
}
return false;
@ -1688,6 +1716,12 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
case WIRE_HSM_SIGN_MUTUAL_CLOSE_TX:
return handle_sign_mutual_close_tx(conn, c, c->msg_in);
#if DEVELOPER
case WIRE_HSM_DEV_MEMLEAK:
return handle_memleak(conn, c, c->msg_in);
#else
case WIRE_HSM_DEV_MEMLEAK:
#endif /* DEVELOPER */
case WIRE_HSM_ECDH_RESP:
case WIRE_HSM_CANNOUNCEMENT_SIG_REPLY:
case WIRE_HSM_CUPDATE_SIG_REPLY:
@ -1703,6 +1737,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
case WIRE_HSM_GET_PER_COMMITMENT_POINT_REPLY:
case WIRE_HSM_CHECK_FUTURE_SECRET_REPLY:
case WIRE_HSM_GET_CHANNEL_BASEPOINTS_REPLY:
case WIRE_HSM_DEV_MEMLEAK_REPLY:
break;
}

View File

@ -7,7 +7,9 @@
#include <common/memleak.h>
#include <common/timeout.h>
#include <connectd/gen_connect_wire.h>
#include <errno.h>
#include <gossipd/gen_gossip_wire.h>
#include <hsmd/gen_hsm_wire.h>
#include <lightningd/chaintopology.h>
#include <lightningd/jsonrpc.h>
#include <lightningd/jsonrpc_errors.h>
@ -16,6 +18,7 @@
#include <lightningd/param.h>
#include <lightningd/subd.h>
#include <stdio.h>
#include <wire/wire_sync.h>
static void json_add_ptr(struct json_stream *response, const char *name,
const void *ptr)
@ -228,11 +231,35 @@ static void connect_dev_memleak_done(struct subd *connectd,
-1, 0, gossip_dev_memleak_done, cmd);
}
static void hsm_dev_memleak_done(struct subd *hsmd,
const u8 *reply,
struct command *cmd)
{
struct lightningd *ld = cmd->ld;
bool found_leak;
if (!fromwire_hsm_dev_memleak_reply(reply, &found_leak)) {
command_fail(cmd, LIGHTNINGD, "Bad hsm_dev_memleak");
return;
}
if (found_leak) {
report_leak_info(cmd, hsmd);
return;
}
/* No leak? Ask connectd. */
subd_req(ld->connectd, ld->connectd,
take(towire_connect_dev_memleak(NULL)),
-1, 0, connect_dev_memleak_done, cmd);
}
static void json_memleak(struct command *cmd,
const char *buffer UNNEEDED,
const jsmntok_t *params UNNEEDED)
{
struct lightningd *ld = cmd->ld;
u8 *msg;
if (!param(cmd, buffer, params, NULL))
return;
@ -243,10 +270,16 @@ static void json_memleak(struct command *cmd,
return;
}
subd_req(ld->connectd, ld->connectd,
take(towire_connect_dev_memleak(NULL)),
-1, 0, connect_dev_memleak_done, cmd);
/* For simplicity, we mark pending, though an error may complete it
* immediately. */
command_still_pending(cmd);
/* We talk to hsm sync. */
msg = towire_hsm_dev_memleak(NULL);
if (!wire_sync_write(ld->hsm_fd, take(msg)))
fatal("Could not write to HSM: %s", strerror(errno));
hsm_dev_memleak_done(ld->hsm, wire_sync_read(tmpctx, ld->hsm_fd), cmd);
}
static const struct json_command dev_memleak_command = {