Quelqu'un sur Internet se trompe
Il y a cinq jours au plus tard, des nouvelles sont parues sur Habré sous le titre " Une vulnérabilité M1RACLES a été trouvée dans Apple M1 - un transfert rapide de données cachées entre les applications est possible ". En une phrase, l'essence est formulée comme suit : dans l'Apple M1, ils ont trouvé un registre que n'importe qui peut lire et écrire en mode non privilégié. Cela signifie qu'il peut être utilisé pour échanger des données en contournant les mécanismes de communication interprocessus fournis par le système d'exploitation. Cependant, l'auteur lui-même ne considère pas cette fonctionnalité comme une vulnérabilité significative, comme il l'écrit dans le commentaire explicatif :
Alors quel est l'intérêt de ce site ?
Se moquer de la façon dont les rapports de vulnérabilité sur les appâts aux clics infosec sont devenus ridicules ces derniers temps. Ce n'est pas parce qu'il a un site Web tape-à-l'œil ou qu'il fait l'actualité que vous devez vous en soucier.
Si vous avez lu jusqu'ici, félicitations ! Vous êtes l'une des rares personnes à ne pas retweeter uniquement en fonction du titre de la page :-)
Mais comment les journalistes sont-ils censés savoir quels bugs sont mauvais et quels bugs ne le sont pas ?
Parle à des gens. En particulier, parlez à des personnes autres que celles qui ont découvert le bogue. Ce dernier peut être honnête ou non sur l'impact réel.
Si vous entendez les mots « canal secret »… c'est probablement surmédiatisé. La plupart d'entre eux proviennent d'usines de papier qui recyclent sans cesse le même concept avec un impact pratique sur la sécurité approximativement nul. Les titres sont généralement des pièges à clics, et parfois carrément trompeurs.
: - ? @SergeyMax @wataru , , , . @creker @adjachenko, , M1RACLES.
. PoC ~500 C++, . , , M1RACLES .
, .
: , , , . , MMU, , , .
M1RACLES, Apple . , . ; PoC, , , , RAM ( ), ..
, :
void drivePHY(const bool level, const std::chrono::nanoseconds duration)
{
static auto deadline = std::chrono::steady_clock::now();
deadline += duration; //
if (level) //
{
std::atomic<bool> finish = false;
const auto loop = [&finish]() {
while (!finish) { }
};
static const auto thread_count = std::max<unsigned>(1, std::thread::hardware_concurrency());
std::vector<std::thread> pool;
for (auto i = 0U; i < (thread_count - 1); i++)
{
pool.emplace_back(loop);
}
while (std::chrono::steady_clock::now() < deadline) { }
finish = true;
for (auto& t : pool)
{
t.join();
}
}
else // --
{
std::this_thread::sleep_for(deadline - std::chrono::steady_clock::now());
}
}
, . , API CPU core affinity (macOS, , ), , . , API affinity , , :
#include <pthread.h> // -lpthread
cpu_set_t cpuset{};
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
, :
constexpr std::chrono::nanoseconds ChipPeriod{16'000'000}; // . 1...100
std::bitset<CDMACodeLength> CDMACode("..."); //
void emitBit(const bool value)
{
for (auto i = 0U; i < CDMACode.size(); i++)
{
const bool bit = value ^ !CDMACode[i];
drivePHY(bit, ChipPeriod);
}
}
( ) , , ( ):
void emitByte(const std::uint8_t data)
{
emitBit(1); //
auto i = 8U; //
while (i --> 0)
{
emitBit((static_cast<std::uintmax_t>(data) & (1ULL << i)) != 0U);
}
}
void emitFrameDelimiter()
{
for (auto i = 0U; i < 20; i++) // 9
{
emitBit(0);
}
}
CRC-16-CCITT:
void emitPacket(const std::vector<std::uint8_t>& data)
{
emitFrameDelimiter();
std::uint16_t crc = CRCInitial;
for (auto v : data)
{
emitByte(v);
crc = crcAdd(crc, v);
}
emitByte(static_cast<std::uint8_t>(crc >> 8U));
emitByte(static_cast<std::uint8_t>(crc >> 0U));
emitFrameDelimiter();
}
- , — .
, - . , . , ( ) :
bool readPHY()
{
static auto deadline = std::chrono::steady_clock::now(); // .
deadline += SampleDuration;
const auto started_at = std::chrono::steady_clock::now();
std::vector<std::int64_t> counters;
const auto loop = [&counters](std::uint32_t index) {
auto& cnt = counters.at(index);
while (std::chrono::steady_clock::now() < deadline)
{
cnt++;
}
};
static const auto thread_count = std::max<unsigned>(1, std::thread::hardware_concurrency());
if (thread_count > 1)
{
counters.resize(thread_count, 0);
std::vector<std::thread> pool;
for (auto i = 0U; i < thread_count; i++)
{
pool.emplace_back(loop, i);
}
for (auto& t : pool)
{
t.join();
}
}
else
{
counters.push_back(0);
loop(0);
}
const double elapsed_ns =
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - started_at).count();
const double rate = double(std::accumulate(std::begin(counters), std::end(counters), 0)) / elapsed_ns;
static double rate_average = rate;
rate_average += (rate - rate_average) / PHYAveragingFactor;
return rate < rate_average; //
}
, , , , . (.., ) , .
, . , . () , .
CDMA , :
. , . ; , , . , .
: , . , .
. . , ; , , .
. , , , .
, , , , , . - LDPC , .
, , . , :
https://github.com/pavel-kirienko/cpu-load-side-channel
:
, ffmpeg ( 4K ), ~30 , . () , .
: , 16 , 1023 , .., 16 , 0.06 . CRC . - ?
M1RACLES ( 8 Mb/s), . - ( 0 b/s), .
, . , . , , ChipPeriod
CDMACodeLength
PoC ( Manjaro 5.4 Intel Core i7 990X @ 4 GHz).
( ) -, . , , , ; , . .
(airgapped networks), Mordechai Guri . , , , , , .
/r/netsec , Hector Martin, M1RACLES. : ; M1RACLES , , . , -, ; , "" .
, , . Hector Martin , , , . , , , M1RACLES , - . :
We already know all systems are vulnerable to certain side-channel attacks. In particular, all systems with shared resources have side channels. Those side channels are easy to turn into covert channels, as you did. The bandwidth, and the severity, is proportional to how closely coupled the security domains are (as you found out, where the VM boundary reduces your performance). As the severity gets higher, you go from 1 bit per second covert channels, to megabytes per second covert channels, to actually being able to steal data from noncooperative entities (actual dangerous side channels) under increasingly less demanding circumstances.
[...]
So M1RACLES is interesting because it is not a side channel - so it poses no danger of leaking data from unwitting processes - but it is a highly efficient covert channel, which does matter under a very small but not nonexistent set of attack scenarios. Does it add covert channel capability where none existed prior? No. But that doesn't mean it's not a vulnerability; as I said, we don't qualify systems on some kind of absolute "vulnerable/not vulnerable" scale. We look at individual issues and then figure out how they affect the overall security of the system under certain attack scenarios.
Mordechai Guri, . , , . , .
:
.
, .
M1RACLES , .