Transferring a file between isolated virtual machines via side channels

Someone on the internet is wrong

Not later than five days ago, news appeared on Habré under the heading " M1RACLES vulnerability was found in Apple M1 - fast hidden data transfer between applications is possible ." In one sentence, the essence is formulated as follows: in the Apple M1 they found a register that anyone can read and write from non-privileged mode. This means that it can be used to exchange data bypassing the interprocess communication mechanisms provided by the OS. However, the author himself does not consider this feature to be a significant vulnerability, as he writes in the explanatory comment:





So what's the point of this website?

Poking fun at how ridiculous infosec clickbait vulnerability reporting has become lately. Just because it has a flashy website or it makes the news doesn't mean you need to care.



If you've read all the way to here, congratulations! You're one of the rare people who doesn't just retweet based on the page title :-)



But how are journalists supposed to know which bugs are bad and which bugs aren't?

Talk to people. In particular, talk to people other than the people who discovered the bug. The latter may or may not be honest about the real impact.



If you hear the words “covert channel”… it's probably overhyped. Most of these come from paper mills who are endlessly recycling the same concept with approximately zero practical security impact. The titles are usually clickbait, and sometimes downright deceptive.





: - ? @SergeyMax @wataru , , , . @creker @adjachenko, , M1RACLES.





. PoC ~500 C++, . , , M1RACLES .





, .





: , , , . , MMU, , , .





M1RACLES, Apple . , . ; PoC, , , , RAM ( ), ..





, . - , ; ( ) . .





By Ivajkin Timofej (translated from the english wiki) - en.wikipedia.org, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=15444663
: Ivajkin Timofej (translated from the english wiki) - en.wikipedia.org, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=15444663

, :





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 , :





Schematic diagram of the receiving path

. , . ; , , . , .





: , . , .





. . , ; , , .





, , GPS . , GPS ( Qx , ):





Diagram from Principles of GNSS, inertial, and multisensor integrated navigation systems, PD Groves, 2nd ed.
"Principles of GNSS, inertial, and multisensor integrated navigation systems", P. D. Groves, 2- .

. , , , .





, , , , , . - 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 , .








All Articles