Browse Source

Track all dynamically allocated memory within the work struct by copying work structs in a common place, creating freshly allocated heap ram for all arrays within the copied struct.

Clear all work structs from the same place to ensure memory does not leak from arrays within the struct.
Convert the gbt coinbase and stratum strings within the work struct to heap ram.
This will allow arbitrary lengths without an upper limit for the strings, preventing the overflows that happen with GBT.
nfactor-troky
Con Kolivas 12 years ago
parent
commit
2d35ac2567
  1. 98
      cgminer.c
  2. 2
      driver-modminer.c
  3. 7
      driver-opencl.c
  4. 14
      miner.h

98
cgminer.c

@ -239,7 +239,7 @@ int swork_id;
struct stratum_share { struct stratum_share {
UT_hash_handle hh; UT_hash_handle hh;
bool block; bool block;
struct work work; struct work *work;
int id; int id;
}; };
@ -1469,9 +1469,7 @@ static void calc_diff(struct work *work, int known);
static void gen_gbt_work(struct pool *pool, struct work *work) static void gen_gbt_work(struct pool *pool, struct work *work)
{ {
unsigned char *merkleroot; unsigned char *merkleroot;
char *cbhex;
memset(work->job_id, 0, 64);
mutex_lock(&pool->gbt_lock); mutex_lock(&pool->gbt_lock);
__build_gbt_coinbase(pool); __build_gbt_coinbase(pool);
merkleroot = __gbt_merkleroot(pool); merkleroot = __gbt_merkleroot(pool);
@ -1483,15 +1481,13 @@ static void gen_gbt_work(struct pool *pool, struct work *work)
memcpy(work->target, pool->gbt_target, 32); memcpy(work->target, pool->gbt_target, 32);
cbhex = bin2hex(pool->gbt_coinbase, pool->coinbase_len); work->gbt_coinbase = bin2hex(pool->gbt_coinbase, pool->coinbase_len);
sprintf(work->gbt_coinbase, "%s", cbhex);
free(cbhex);
/* For encoding the block data on submission */ /* For encoding the block data on submission */
work->gbt_txns = pool->gbt_txns + 1; work->gbt_txns = pool->gbt_txns + 1;
if (pool->gbt_workid) if (pool->gbt_workid)
sprintf(work->job_id, "%s", pool->gbt_workid); work->job_id = strdup(pool->gbt_workid);
mutex_unlock(&pool->gbt_lock); mutex_unlock(&pool->gbt_lock);
memcpy(work->data + 4 + 32, merkleroot, 32); memcpy(work->data + 4 + 32, merkleroot, 32);
@ -2307,7 +2303,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
/* build JSON-RPC request */ /* build JSON-RPC request */
if (work->gbt) { if (work->gbt) {
char gbt_block[1024], *varint, *header; char gbt_block[4096], *varint, *header;
unsigned char data[80]; unsigned char data[80];
flip80(data, work->data); flip80(data, work->data);
@ -2334,7 +2330,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
free(varint); free(varint);
strcat(gbt_block, work->gbt_coinbase); strcat(gbt_block, work->gbt_coinbase);
if (strlen(work->job_id)) if (work->job_id)
sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {\"workid\": \"%s\"}]}", gbt_block, work->job_id); sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {\"workid\": \"%s\"}]}", gbt_block, work->job_id);
else else
sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {}]}", gbt_block); sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {}]}", gbt_block);
@ -2634,8 +2630,25 @@ static struct work *make_work(void)
return work; return work;
} }
static void free_work(struct work *work) /* This is the central place all work that is about to be retired should be
* cleaned to remove any dynamically allocated arrays within the struct */
void clean_work(struct work *work)
{
free(work->job_id);
free(work->nonce2);
free(work->ntime);
free(work->gbt_coinbase);
work->job_id = NULL;
work->nonce2 = NULL;
work->ntime = NULL;
work->gbt_coinbase = NULL;
}
/* All dynamically allocated work structs should be freed here to not leak any
* ram from arrays allocated within the work struct */
void free_work(struct work *work)
{ {
clean_work(work);
free(work); free(work);
} }
@ -2948,11 +2961,37 @@ static void roll_work(struct work *work)
work->id = total_work++; work->id = total_work++;
} }
/* Duplicates any dynamically allocated arrays within the work struct to
* prevent a copied work struct from freeing ram belonging to another struct */
void __copy_work(struct work *work, struct work *base_work)
{
clean_work(work);
memcpy(work, base_work, sizeof(struct work));
if (work->job_id)
work->job_id = strdup(base_work->job_id);
if (work->nonce2)
work->nonce2 = strdup(base_work->nonce2);
if (work->ntime)
work->ntime = strdup(base_work->ntime);
if (work->gbt_coinbase)
work->gbt_coinbase = strdup(base_work->gbt_coinbase);
}
/* Generates a copy of an existing work struct, creating fresh heap allocations
* for all dynamically allocated arrays within the struct */
struct work *copy_work(struct work *base_work)
{
struct work *work = make_work();
__copy_work(work, base_work);
return work;
}
static struct work *make_clone(struct work *work) static struct work *make_clone(struct work *work)
{ {
struct work *work_clone = make_work(); struct work *work_clone = copy_work(work);
memcpy(work_clone, work, sizeof(struct work));
work_clone->clone = true; work_clone->clone = true;
gettimeofday((struct timeval *)&(work_clone->tv_cloned), NULL); gettimeofday((struct timeval *)&(work_clone->tv_cloned), NULL);
work_clone->longpoll = false; work_clone->longpoll = false;
@ -3016,7 +3055,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work);
static void *get_work_thread(void *userdata) static void *get_work_thread(void *userdata)
{ {
struct workio_cmd *wc = (struct workio_cmd *)userdata; struct workio_cmd *wc = (struct workio_cmd *)userdata;
struct work *ret_work= NULL; struct work *ret_work = NULL;
struct curl_ent *ce = NULL; struct curl_ent *ce = NULL;
struct pool *pool; struct pool *pool;
@ -3232,7 +3271,7 @@ static void *submit_work_thread(void *userdata)
char *noncehex; char *noncehex;
char s[1024]; char s[1024];
memcpy(&sshare->work, work, sizeof(struct work)); sshare->work = copy_work(work);
mutex_lock(&sshare_lock); mutex_lock(&sshare_lock);
/* Give the stratum share a unique id */ /* Give the stratum share a unique id */
sshare->id = swork_id++; sshare->id = swork_id++;
@ -4538,7 +4577,7 @@ out_unlock:
static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val, static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val,
struct stratum_share *sshare) struct stratum_share *sshare)
{ {
struct work *work = &sshare->work; struct work *work = sshare->work;
uint64_t sharediff = share_diff(work); uint64_t sharediff = share_diff(work);
char hashshow[65]; char hashshow[65];
uint32_t *hash32; uint32_t *hash32;
@ -4602,6 +4641,7 @@ static bool parse_stratum_response(struct pool *pool, char *s)
goto out; goto out;
} }
stratum_share_result(val, res_val, err_val, sshare); stratum_share_result(val, res_val, err_val, sshare);
free_work(sshare->work);
free(sshare); free(sshare);
ret = true; ret = true;
@ -4621,8 +4661,9 @@ static void clear_stratum_shares(struct pool *pool)
mutex_lock(&sshare_lock); mutex_lock(&sshare_lock);
HASH_ITER(hh, stratum_shares, sshare, tmpshare) { HASH_ITER(hh, stratum_shares, sshare, tmpshare) {
if (sshare->work.pool == pool) { if (sshare->work->pool == pool) {
HASH_DEL(stratum_shares, sshare); HASH_DEL(stratum_shares, sshare);
free_work(sshare->work);
free(sshare); free(sshare);
cleared++; cleared++;
} }
@ -5129,17 +5170,13 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
{ {
unsigned char *coinbase, merkle_root[32], merkle_sha[64], *merkle_hash; unsigned char *coinbase, merkle_root[32], merkle_sha[64], *merkle_hash;
int len, cb1_len, n1_len, cb2_len, i; int len, cb1_len, n1_len, cb2_len, i;
char header[260], *nonce2;
uint32_t *data32, *swap32; uint32_t *data32, *swap32;
char header[260];
memset(work->job_id, 0, 64);
memset(work->nonce2, 0, 64);
memset(work->ntime, 0, 16);
mutex_lock(&pool->pool_lock); mutex_lock(&pool->pool_lock);
/* Generate coinbase */ /* Generate coinbase */
nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size); work->nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size);
pool->nonce2++; pool->nonce2++;
cb1_len = strlen(pool->swork.coinbase1) / 2; cb1_len = strlen(pool->swork.coinbase1) / 2;
n1_len = strlen(pool->nonce1) / 2; n1_len = strlen(pool->nonce1) / 2;
@ -5148,7 +5185,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
coinbase = alloca(len + 1); coinbase = alloca(len + 1);
hex2bin(coinbase, pool->swork.coinbase1, cb1_len); hex2bin(coinbase, pool->swork.coinbase1, cb1_len);
hex2bin(coinbase + cb1_len, pool->nonce1, n1_len); hex2bin(coinbase + cb1_len, pool->nonce1, n1_len);
hex2bin(coinbase + cb1_len + n1_len, nonce2, pool->n2size); hex2bin(coinbase + cb1_len + n1_len, work->nonce2, pool->n2size);
hex2bin(coinbase + cb1_len + n1_len + pool->n2size, pool->swork.coinbase2, cb2_len); hex2bin(coinbase + cb1_len + n1_len + pool->n2size, pool->swork.coinbase2, cb2_len);
/* Generate merkle root */ /* Generate merkle root */
@ -5181,10 +5218,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
work->sdiff = pool->swork.diff; work->sdiff = pool->swork.diff;
/* Copy parameters required for share submission */ /* Copy parameters required for share submission */
sprintf(work->job_id, "%s", pool->swork.job_id); work->job_id = strdup(pool->swork.job_id);
sprintf(work->nonce2, "%s", nonce2); work->ntime = strdup(pool->swork.ntime);
sprintf(work->ntime, "%s", pool->swork.ntime);
free(nonce2);
mutex_unlock(&pool->pool_lock); mutex_unlock(&pool->pool_lock);
@ -5225,6 +5260,8 @@ static void get_work(struct work *work, struct thr_info *thr, const int thr_id)
* should not be restarted */ * should not be restarted */
thread_reportout(thr); thread_reportout(thr);
clean_work(work);
if (opt_benchmark) { if (opt_benchmark) {
get_benchmark_work(work); get_benchmark_work(work);
goto out; goto out;
@ -5298,7 +5335,7 @@ retry:
pool_resus(pool); pool_resus(pool);
} }
memcpy(work, work_heap, sizeof(struct work)); __copy_work(work, work_heap);
free_work(work_heap); free_work(work_heap);
out: out:
@ -5307,7 +5344,7 @@ out:
work->mined = true; work->mined = true;
} }
bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct timeval *tv_work_found) bool submit_work_sync(struct thr_info *thr, struct work *work_in, struct timeval *tv_work_found)
{ {
struct workio_cmd *wc; struct workio_cmd *wc;
@ -5318,10 +5355,9 @@ bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct t
return false; return false;
} }
wc->work = make_work(); wc->work = copy_work(work_in);
wc->cmd = WC_SUBMIT_WORK; wc->cmd = WC_SUBMIT_WORK;
wc->thr = thr; wc->thr = thr;
memcpy(wc->work, work_in, sizeof(*work_in));
if (tv_work_found) if (tv_work_found)
memcpy(&(wc->work->tv_work_found), tv_work_found, sizeof(struct timeval)); memcpy(&(wc->work->tv_work_found), tv_work_found, sizeof(struct timeval));

2
driver-modminer.c

@ -645,7 +645,7 @@ static int64_t modminer_scanhash(struct thr_info *thr, struct work *work, int64_
if (startwork) { if (startwork) {
if (!modminer_start_work(thr)) if (!modminer_start_work(thr))
return -1; return -1;
memcpy(&state->running_work, work, sizeof(state->running_work)); __copy_work(&state->running_work, work);
} }
// This is intentionally early // This is intentionally early

7
driver-opencl.c

@ -1464,10 +1464,8 @@ static void opencl_free_work(struct thr_info *thr, struct work *work)
clFinish(clState->commandQueue); clFinish(clState->commandQueue);
if (thrdata->res[FOUND]) { if (thrdata->res[FOUND])
thrdata->last_work = &thrdata->_last_work; thrdata->last_work = copy_work(&thrdata->_last_work);
memcpy(thrdata->last_work, work, sizeof(*thrdata->last_work));
}
} }
static bool opencl_prepare_work(struct thr_info __maybe_unused *thr, struct work *work) static bool opencl_prepare_work(struct thr_info __maybe_unused *thr, struct work *work)
@ -1535,6 +1533,7 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
if (unlikely(thrdata->last_work)) { if (unlikely(thrdata->last_work)) {
applog(LOG_DEBUG, "GPU %d found something in last work?", gpu->device_id); applog(LOG_DEBUG, "GPU %d found something in last work?", gpu->device_id);
postcalc_hash_async(thr, thrdata->last_work, thrdata->res); postcalc_hash_async(thr, thrdata->last_work, thrdata->res);
free_work(thrdata->last_work);
thrdata->last_work = NULL; thrdata->last_work = NULL;
} else { } else {
applog(LOG_DEBUG, "GPU %d found something?", gpu->device_id); applog(LOG_DEBUG, "GPU %d found something?", gpu->device_id);

14
miner.h

@ -962,15 +962,13 @@ struct work {
bool queued; bool queued;
bool stratum; bool stratum;
/* These are arbitrary lengths as it is too hard to keep track of char *job_id;
* dynamically allocated ram in work structs */ char *nonce2;
char job_id[64]; char *ntime;
char nonce2[64];
char ntime[16];
double sdiff; double sdiff;
bool gbt; bool gbt;
char gbt_coinbase[512]; char *gbt_coinbase;
int gbt_txns; int gbt_txns;
unsigned int work_block; unsigned int work_block;
@ -1031,6 +1029,10 @@ extern void tq_thaw(struct thread_q *tq);
extern bool successful_connect; extern bool successful_connect;
extern void adl(void); extern void adl(void);
extern void app_restart(void); extern void app_restart(void);
extern void clean_work(struct work *work);
extern void free_work(struct work *work);
extern void __copy_work(struct work *work, struct work *base_work);
extern struct work *copy_work(struct work *base_work);
enum api_data_type { enum api_data_type {
API_ESCAPE, API_ESCAPE,

Loading…
Cancel
Save