Efficient Memory Safety for TinyOS Nathan Cooprider Will Archer Eric Eide David Gay† John Regehr University of Utah School of Computing †Intel Research Berkeley 1 Suppose we have a WSN… ● What happened? – – State got corrupted Hard to debug ● ● Limited visibility into executing systems Difficult to replicate complex bugs 2 Goal ● Catch all pointer and array bounds errors – ● ● Before they corrupt state Provide a choice of recovery action Put WSN software development on a solid foundation 3 Our contribution: Safe TinyOS Expand • Modify TinyOS to work with Deputy Enforce Deputy’s safety Deputy: Practical• for model under concurrency deployment existing solution • Reduce overhead for making C safe into system safety – 5.2% duty cycle increase – 13% code size increase 4 Example builds $ make mica2 $ make mica2 safe $ make mica2 safe optimize 5 Language safety Language safety System safety Deputy Our work Safe TinyOS ● Deputy is the starting point – – – Safe C dialect developed at Berkeley Annotations exploit values present in code to specify bounds/etc information Translates a C program into a safe C program by inserting safety checks 6 Annotations in nesC Example interface from TinyOS 2 /* Buffered high data rate reading, usually from sensor devices */ interface ReadStream<val_t> { command error_t postBuffer(val_t* buf, uint16_t n); command error_t read(uint32_t usPeriod); event void bufferDone(error_t result, val_t* buf, uint16_t n); event void readDone(error_t result, uint32_t usActualPeriod); } 7 Annotations in nesC COUNT Either null or array /* Buffered high data rate reading, usually from sensor devices */ interface ReadStream<val_t> { command error_t postBuffer(val_t* COUNT(n) buf, uint16_t n); command error_t read(uint32_t usPeriod); event void bufferDone(error_t result, val_t* COUNT(n) buf, uint16_t n); event void readDone(error_t result, uint32_t usActualPeriod); } 8 Few lines changed ● 253 nesC files – ● 16/2541 or 0.63% Application lines 26,022 loc 133/20455 or 0.65% TinyOS Component lines 0.74% changed – 1 in 135 lines 23% 8% 44/3026 or 1.5% TinyOS Interface lines Applications TinyOS Components TinyOS Interfaces 69% 9 run modified nesC compiler enforce safety using Deputy deal with concurrency ● ● Atomic block Concurrency Deputy enforces safety in sequential code Static analysis to avoid extraneous protection – Potentially unsafe read to local Interrupt Deputy check Potentially Read local ) If ( unsafe read Few actually need protection 10 Compress error messages run modified nesC compiler ● – enforce safety using Deputy – ● deal with concurrency compress error messages 0x0773 Deputy’s verbose messages Use precious memory No screen on the mote Replaced with integer ID – – Fault location identifiers, FLIDs FLIDs blinked on LEDs or sent to network tos/chips/cc2420/CC2420ReceiveP.nc: 241: decode CC2420ReceiveP$receiveDone_task$runTask: Assertion failed in upper bound coercion: FLID CC2420ReceiveP$m_p_rx_buf->data + length <= CC2420ReceiveP$m_p_rx_buf + 28 11 Code improvements run modified nesC compiler ● Dataflow analysis – – enforce safety using Deputy – Interprocedural and whole-program Simultaneous pointer analysis Handles concurrent programs ● deal with concurrency compress error messages whole-program optimization ● Propagate data through globals More aggressive than gcc is, or can be: – Inlining – Dead code elimination – Value propagation – Synchronization removal 12 Safe TinyOS toolchain run modified nesC compiler enforce safety using Deputy deal with concurrency compress error messages Safe whole-program optimization TinyOS app TinyOS code Annotate Safe TinyOS code Modify TinyOS to work with Deputy Enforce Deputy’s safety model under concurrency Reduce overhead 13 Resource usage ● Six TinyOS 2 benchmarks – ● No RAM usage increase – – ● 3,561 to 25,773 lines of C code Deputy exploits existing bounds info. Optimizer saves a little RAM Duty cycle obtained with Avrora simulator – Duty cycle = % of time processor is on 14 Code size 15 Code size 35% 13% -11% 16 Duty cycle 24% 5.2% -9.7% 17 On to bug hunting ● ● ● Ran Safe TinyOS applications on motes Found four bugs Will talk about three of them 18 A bug Buffer length Safety violation Serial caught by Dispatcher Safe TinyOS ● Serial stack – passed in a buffer – ● ● Passes along one byte at a time Problem: given buffer length too large Out-of-bounds index for buffer 19 Another bug ● Active Message Queue – ● ● Queue moves on to next client on send done event With no clients – – ● Scheduling of network link Spurious report of completion Invalid array index Difficult to replicate – Several minutes, many nodes Send Send Send done done done 0 3 2 1 Current Safety violation caught by Safe TinyOS 20 Yet another bug for (i = 0; i < NUM_BUFFERS; i++) { if (m_pool[i].msg == NULL) break; } i can point to one past end of buffer if (m_pool[i].msg == NULL) { m_pool[i].msg = _msg; } ● ● ● Time synchronization and leader election Upon discovery Array out-of-bounds access Difficult to locate Bug already fixed in latest release – After 20 of minutes third-party component – In “third-party” networking code 21 Increased availability Array Out-of-bounds Normal TinyOS Array Out-of-bounds Safe TinyOS Normal TinyOS: 0% average availability Safe TinyOS: 95% average availability Rebuild Soft state Reboot 22 Conclusion ● Type and memory safety is practical for tiny embedded systems – – – Safety for entire system Low run-time cost compared to original unsafe applications Can easily fit into existing programming practice We plan to make it available soon… 23