simplewallet: plug a timing leak
As reported by Tramèr et al, timing of refresh requests can be used to see whether a password was requested (and thus at least one output received) since this will induce a delay in subsequent calls. To avoid this, we schedule calls at a given time instead of sleeping for a set time (which would make delays additive). To further avoid a scheduled call being during the time in which a password is prompted, the actual scheduled time is now randomized.
This commit is contained in:
parent
dcff02e4c3
commit
38f6910481
|
@ -8807,22 +8807,41 @@ void simple_wallet::check_for_messages()
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void simple_wallet::wallet_idle_thread()
|
void simple_wallet::wallet_idle_thread()
|
||||||
{
|
{
|
||||||
|
const boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::universal_time();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> lock(m_idle_mutex);
|
boost::unique_lock<boost::mutex> lock(m_idle_mutex);
|
||||||
if (!m_idle_run.load(std::memory_order_relaxed))
|
if (!m_idle_run.load(std::memory_order_relaxed))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifndef _WIN32
|
// if another thread was busy (ie, a foreground refresh thread), we'll end up here at
|
||||||
m_inactivity_checker.do_call(boost::bind(&simple_wallet::check_inactivity, this));
|
// some random time that's not what we slept for, so we should not call refresh now
|
||||||
|
// or we'll be leaking that fact through timing
|
||||||
|
const boost::posix_time::ptime now0 = boost::posix_time::microsec_clock::universal_time();
|
||||||
|
const uint64_t dt_actual = (now0 - start_time).total_microseconds() % 1000000;
|
||||||
|
#ifdef _WIN32
|
||||||
|
static const uint64_t threshold = 10000;
|
||||||
|
#else
|
||||||
|
static const uint64_t threshold = 2000;
|
||||||
#endif
|
#endif
|
||||||
m_refresh_checker.do_call(boost::bind(&simple_wallet::check_refresh, this));
|
if (dt_actual < threshold) // if less than a threshold... would a very slow machine always miss it ?
|
||||||
m_mms_checker.do_call(boost::bind(&simple_wallet::check_mms, this));
|
{
|
||||||
m_rpc_payment_checker.do_call(boost::bind(&simple_wallet::check_rpc_payment, this));
|
#ifndef _WIN32
|
||||||
|
m_inactivity_checker.do_call(boost::bind(&simple_wallet::check_inactivity, this));
|
||||||
|
#endif
|
||||||
|
m_refresh_checker.do_call(boost::bind(&simple_wallet::check_refresh, this));
|
||||||
|
m_mms_checker.do_call(boost::bind(&simple_wallet::check_mms, this));
|
||||||
|
m_rpc_payment_checker.do_call(boost::bind(&simple_wallet::check_rpc_payment, this));
|
||||||
|
|
||||||
if (!m_idle_run.load(std::memory_order_relaxed))
|
if (!m_idle_run.load(std::memory_order_relaxed))
|
||||||
break;
|
break;
|
||||||
m_idle_cond.wait_for(lock, boost::chrono::seconds(1));
|
}
|
||||||
|
|
||||||
|
// aim for the next multiple of 1 second
|
||||||
|
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
|
||||||
|
const auto dt = (now - start_time).total_microseconds();
|
||||||
|
const auto wait = 1000000 - dt % 1000000;
|
||||||
|
m_idle_cond.wait_for(lock, boost::chrono::microseconds(wait));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -448,10 +448,12 @@ namespace cryptonote
|
||||||
std::atomic<bool> m_locked;
|
std::atomic<bool> m_locked;
|
||||||
std::atomic<bool> m_in_command;
|
std::atomic<bool> m_in_command;
|
||||||
|
|
||||||
|
template<uint64_t mini, uint64_t maxi> struct get_random_interval { public: uint64_t operator()() const { return crypto::rand_range(mini, maxi); } };
|
||||||
|
|
||||||
epee::math_helper::once_a_time_seconds<1> m_inactivity_checker;
|
epee::math_helper::once_a_time_seconds<1> m_inactivity_checker;
|
||||||
epee::math_helper::once_a_time_seconds<90> m_refresh_checker;
|
epee::math_helper::once_a_time_seconds_range<get_random_interval<80 * 1000000, 100 * 1000000>> m_refresh_checker;
|
||||||
epee::math_helper::once_a_time_seconds<90> m_mms_checker;
|
epee::math_helper::once_a_time_seconds_range<get_random_interval<90 * 1000000, 110 * 1000000>> m_mms_checker;
|
||||||
epee::math_helper::once_a_time_seconds<90> m_rpc_payment_checker;
|
epee::math_helper::once_a_time_seconds_range<get_random_interval<90 * 1000000, 115 * 1000000>> m_rpc_payment_checker;
|
||||||
|
|
||||||
std::atomic<bool> m_need_payment;
|
std::atomic<bool> m_need_payment;
|
||||||
boost::posix_time::ptime m_last_rpc_payment_mining_time;
|
boost::posix_time::ptime m_last_rpc_payment_mining_time;
|
||||||
|
|
Loading…
Reference in New Issue