Better input validation

This commit is contained in:
Kagami Hiiragi 2015-01-11 05:59:32 +03:00
parent 12066842cc
commit e3765b81fc
4 changed files with 42 additions and 34 deletions

View File

@ -56,14 +56,14 @@ exports.pow = function(opts) {
// Check all input params prematurely to not let promise executor or // Check all input params prematurely to not let promise executor or
// worker to fail because of it. // worker to fail because of it.
// 1 - UINT32_MAX assert(typeof poolSize === "number", "Bad pool size");
assert(poolSize > 0, "Pool size is too low"); assert(poolSize >= 1, "Pool size is too low");
assert(poolSize <= 4294967295, "Pool size is too high"); assert(poolSize <= 1024, "Pool size is too high");
// 0 - (2^53 - 1)
assert(typeof opts.target === "number", "Bad target"); assert(typeof opts.target === "number", "Bad target");
assert(opts.target >= 0, "Target is too low"); assert(opts.target >= 0, "Target is too low");
assert(opts.target <= 9007199254740991, "Target is too high"); assert(opts.target <= 9007199254740991, "Target is too high");
assert(Buffer.isBuffer(opts.initialHash), "Bad initial hash"); assert(Buffer.isBuffer(opts.initialHash), "Bad initial hash");
assert(opts.initialHash.length === 64, "Bad initial hash");
// TODO(Kagami): Allow to cancel a POW (see `platform.browser.js`). // TODO(Kagami): Allow to cancel a POW (see `platform.browser.js`).
return new promise(function(resolve, reject) { return new promise(function(resolve, reject) {

View File

@ -9,15 +9,15 @@
#include <pthread.h> #include <pthread.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <openssl/sha.h> #include <openssl/sha.h>
#include "./pow.h"
#define HASH_SIZE 64 enum PowResult {
RESULT_OK = 0,
typedef enum { RESULT_OVERFLOW = -1,
RESULT_NOT_READY, RESULT_ERROR = -2,
RESULT_OK, RESULT_BAD_INPUT = -3,
RESULT_OVERFLOW, RESULT_NOT_READY = -4
RESULT_ERROR };
} Result;
// Global arguments. // Global arguments.
size_t g_pool_size; size_t g_pool_size;
@ -27,7 +27,7 @@ uint64_t g_max_nonce;
// Shared variables for threads. // Shared variables for threads.
pthread_mutex_t g_mutex; pthread_mutex_t g_mutex;
Result g_result = RESULT_NOT_READY; PowResult g_result = RESULT_NOT_READY;
uint64_t g_nonce; uint64_t g_nonce;
inline uint64_t ntohll(uint64_t x) { inline uint64_t ntohll(uint64_t x) {
@ -38,7 +38,7 @@ inline uint64_t ntohll(uint64_t x) {
} }
// Set POW computation result in a thread-safe way. // Set POW computation result in a thread-safe way.
void set_result(Result res, uint64_t nonce) { void set_result(PowResult res, uint64_t nonce) {
pthread_mutex_lock(&g_mutex); pthread_mutex_lock(&g_mutex);
if (g_result == RESULT_NOT_READY) { if (g_result == RESULT_NOT_READY) {
g_result = res; g_result = res;
@ -87,6 +87,9 @@ int pow(size_t pool_size,
const uint8_t* initial_hash, const uint8_t* initial_hash,
uint64_t max_nonce, uint64_t max_nonce,
uint64_t* nonce) { uint64_t* nonce) {
if (pool_size < 1 || pool_size > MAX_POOL_SIZE) {
return RESULT_BAD_INPUT;
}
g_pool_size = pool_size; g_pool_size = pool_size;
g_target = target; g_target = target;
g_initial_hash = (uint8_t *)initial_hash; g_initial_hash = (uint8_t *)initial_hash;
@ -112,18 +115,10 @@ int pow(size_t pool_size,
pthread_join(threads[i], NULL); pthread_join(threads[i], NULL);
} }
switch (g_result) { if (g_result == RESULT_OK) {
case RESULT_OK:
*nonce = g_nonce; *nonce = g_nonce;
error = 0;
break;
case RESULT_OVERFLOW:
error = -1;
break;
default:
error = -2;
} }
pthread_mutex_destroy(&g_mutex); pthread_mutex_destroy(&g_mutex);
return error; return g_result;
} }

View File

@ -1,6 +1,9 @@
#ifndef BITMESSAGE_POW_H #ifndef BITMESSAGE_POW_H
#define BITMESSAGE_POW_H #define BITMESSAGE_POW_H
#define MAX_POOL_SIZE 1024
#define HASH_SIZE 64
int pow(size_t pool_size, int pow(size_t pool_size,
uint64_t target, uint64_t target,
const uint8_t* initial_hash, const uint8_t* initial_hash,

View File

@ -68,22 +68,32 @@ class PowWorker : public NanAsyncWorker {
NAN_METHOD(PowAsync) { NAN_METHOD(PowAsync) {
NanScope(); NanScope();
NanCallback *callback = new NanCallback(args[3].As<Function>()); if (args.Length() != 4 ||
!args[0]->IsNumber() || // pool_size
!args[1]->IsNumber() || // target
!args[2]->IsObject() || // initial_hash
!args[3]->IsFunction()) { // cb
NanThrowError("Bad input");
NanReturnUndefined();
}
size_t pool_size = args[0]->Uint32Value(); size_t pool_size = args[0]->Uint32Value();
uint64_t target = args[1]->IntegerValue(); uint64_t target = args[1]->IntegerValue();
size_t length = Buffer::Length(args[2]->ToObject()); size_t length = Buffer::Length(args[2]->ToObject());
char* buf = Buffer::Data(args[2]->ToObject()); if (pool_size < 1 || pool_size > MAX_POOL_SIZE || length != HASH_SIZE) {
NanThrowError("Bad input");
NanReturnUndefined();
}
uint8_t* initial_hash = (uint8_t *)malloc(length); uint8_t* initial_hash = (uint8_t *)malloc(length);
if (initial_hash == NULL) { if (initial_hash == NULL) {
Local<Value> argv[] = {NanError("Internal error")}; NanThrowError("Internal error");
callback->Call(1, argv); NanReturnUndefined();
} else {
memcpy(initial_hash, buf, length);
NanAsyncQueueWorker(
new PowWorker(callback, pool_size, target, initial_hash));
} }
char* buf = Buffer::Data(args[2]->ToObject());
memcpy(initial_hash, buf, length);
NanCallback* callback = new NanCallback(args[3].As<Function>());
NanAsyncQueueWorker(new PowWorker(callback, pool_size, target, initial_hash));
NanReturnUndefined(); NanReturnUndefined();
} }