1 / 27

Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

Static Analysis to Enforce Safe Value Flow in Embedded Control Systems. DSN 2006 Sumant Kowshik, Grigore Rosu , Lui Sha University of Illinois at Urbana-Champaign. Architectural Isolation of Core Functionality. Case Study: Simplex. Non-core. control. Core cont. Run-time monitor.

Download Presentation

Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Static Analysis to Enforce Safe Value Flow in Embedded Control Systems DSN 2006 Sumant Kowshik, Grigore Rosu, Lui Sha University of Illinois at Urbana-Champaign

  2. Architectural Isolation of Core Functionality Case Study: Simplex Non-core control Core cont. Run-time monitor Core subsystem feedback • Non-core subsystem • Complex and relatively untested • Performance, user-interfaces, optional features • Core subsystem • Simple, well-tested components • Purpose: Safety • Emerging Architectural Principle: Isolation of core functionality from non-core subsystem failures

  3. Architecture  Implementation An Implementation of the Simplex Architecture Core feedback feedback Non-core Safe Cont. control SHM Monitor Platform • Single-threaded programs: Simplex and Non-core controller • Core: Safety controller, run-time monitor, device I/O • Shared Platform; Communicate using Shared Memory (SHM)

  4. Value Flow in Control Systems Core feedback feedback Non-core Safe Cont. control SHM Monitor Platform • Complete isolation of core and non-core components is impractical • In general two-way communication between core and non-core • core to non-core -- feedback information • non-core to core – computed high-performance controls

  5. Monitoring Value Errors in Control • Value errors easier to monitor for recoverability in control systems due to the continuous nature of control variables • Example 1: Controller outputs have a finite bounded effect on physical plant [Cunha, Simplex] • Validity cannot be checked; System recoverability can be checked using inbuilt conservative model • Example 2: Feedback from sensor can have intermittent errors • State estimator uses estimated position as a validation check • Core component should onlyusenon-core data (run-time monitor); should notdependon it [Ding and Sha]

  6. corrupt hogging • Resource Usage: Guaranteeing a set of logical system resources to the core component • System call monitoring; Real-time virtual machines Background: Isolating the Core Component Core feedback feedback Non-core Safe Cont. control SHM Monitor Platform • Memory Safety: Memory errors such as dangling pointers can overwrite and corrupt the core component • Prior Work: Control-C (SAFECode), CCured

  7. Monitoring function Implementation of Value Flow Example: Simplex simplex_ main() { initializeSHM(); lockSHM(); while (1) { readFeedback(F); publishFeedback(F); safetyCtrl = safety_control(F); unlockSHM(); pause(); lockSHM(); output = decision(safetyCtrl, &SHM->non-core, F); sendControl(output); } } SHM Non-core Feedback Feedback Non-core Control Control Output

  8. Implementation Errors I simplex_ main() { initializeSHM(); lockSHM(); while (1) { readFeedback(F); publishFeedback(F); safetyCtrl = safety_control(F); unlockSHM(); pause(); lockSHM(); if (flag) { output = decision(safetyCtrl, &SHM->noncore, F); sendControl(output); } else { sendControl(SHM->noncore); } SHM Feedback Non-core Feedback Non-core Control 1. Unmonitored non-core value: SHM->noncore unmonitored along false path Control Output

  9. Implementation Errors II Example: Simplex simplex_ main() { initializeSHM(); lockSHM(); while (1) { readFeedback(F); publishFeedback(F); safetyCtrl = safety_control(F); unlockSHM(); pause(); lockSHM(); output = decision(safetyCtrl, &SHM->noncore, &SHM->F); sendControl(output); } SHM Feedback Non-core Feedback Non-core Control 2. Hidden Dependencies: SHM->F unknowingly dereferenced Control Output

  10. Implementation Errors III Example: Simplex simplex_ main() { initializeSHM(); lockSHM(); while (1) { readFeedback(F); publishFeedback(F); ref = getReferencePoint(); safetyCtrl = safety_control(F, ref); unlockSHM(); pause(); lockSHM(); output = decision(safetyCtrl, &SHM->noncore ,F); sendControl(output); } } SHM Non-core Feedback Feedback Non-core Control Reference 3. Wrong Assumptions: E.g. Reference will not be corrupted by non-core component Control Output

  11. Assumptions and Goals Goals Make communication with non-core components explicit Enforce that all non-core data is run-time monitored before use in critical data by the core component • Required Assumptions • The run-time monitor for the non-core values is correct! • Communication through shared memory only • Performance critical systems • More challenging scenario

  12. Contributions and Limitations • Annotation language/rigor and accompanying analysis • + Simple, local annotations on C • + Expressive language to program embedded control systems in spite of the usage restrictions • + Purely static analysis to precisely find all unmonitored values from non-core components • Also identifies errors where unmonitored accesses can corrupt critical values even in long-running systems • Few false positives in errors due to control dependency • Wrong annotations can lead to undetected errors

  13. Approach: Monitoring Functions • For all shared variables, x • Noncore.read(x)  safe • Noncore.write(x)  safe • Core.read(x)  warning (error, if x propagates to critical data) • Core.write(x)  safe Core.monitoringRead(x)  safe, within monitoring “zone” if x is declared to be safe to read in it • Monitoring functions can be annotated so that shared variables are safe to read in these functions (and their callees)

  14. Monitoring Functions: assume Annotation simplex_ main() { initializeSHM(); while (1) { readFeedback(F); publishFeedback(F); safetyCtrl = safety_control(F); unlockSHM(); pause(); lockSHM(); output = decision(safetyCtrl, &SHM->non-core, &SHM->F); sendControl(output); } } simplex_ main() { initializeSHM(); while (1) { readFeedback(F); publishFeedback(F); safetyCtrl = safety_control(F); unlockSHM(); pause(); lockSHM(); output = decision(safetyCtrl, &SHM->non-core, &SHM->F); sendControl(output); } } float decision (float safeControl, SHMData *noncore, Feedback *F) { if (checkSafety(F, noncore)) return noncore->control; else return safeControl; } /***SafeFlowAnnot: assume(safe(noncore, 0, sizeof(SHMData))) ***/ Use the assume annotation to specify the safely accessible shared memory locations Simple, local annotation

  15. assert Annotation simplex_ main() { initializeSHM(size); while (1) { readFeedback(F); publishFeedback(F); safetyCtrl = safety_control(F); unlockSHM(); pause(); lockSHM(); output = decision(safetyCtrl, &SHM->non-core, &SHM->F); sendControl(output); } } /***SafeFlowAnnot: assert(safe(output)) ***/ Assert annotation placed before critical data such as control outputs sent to the plant or argument of system calls such as kill

  16. Restrictions on Shared Memory Usage • Shared memory not deallocated until end of main() • Pointers to shared memory • Cannot be cast to incompatible types • Address cannot be taken • Arrays in shared memory • Indices within array bounds • Loop bounds affine w.r.t size of array and loop index variables or vice versa No dangling pointers to shared memory Enforce shared memory pointers not aliased through memory

  17. /***SafeFlow Annotation assume(shminit); ***/ Initialization Function Shared Memory Initialization initializeSHM(size_t size) { void *shmStart; /* Initialize shared memory */ shmid = shmget(SHMKEY, size, flags); shmStart = shmat(shmid, 0, 0); feedback = (SHMData *) shmStart; noncore = feedback + 1; } simplex_ main() { initializeSHM(); while (1) { readFeedback(F); publishFeedback(F); safetyCtrl = safety_control(F); unlockSHM(); pause(); lockSHM(); output = decision(safetyCtrl, &SHM->non-core, &SHM->F); sendControl(output); } } simplex_ main() { initializeSHM(size); while (1) { readFeedback(F); publishFeedback(F); safetyCtrl = safety_control(F); unlockSHM(); pause(); lockSHM(); output = decision(safetyCtrl, &SHM->non-core, &SHM->F); sendControl(output); } } /***SafeFlow Annotation: post-condition assume(non-core(feedback)) assume(non-core(noncore)) assume(size(feedback) = sizeof(SHMData)) assume(size(noncore) = sizeof(SHMData)) ***/ • Language restrictions not applied to initialization function • Unix shared memory initialization is untyped (needs downcasts) • Arrays in shared memory need to be made explicit

  18. Simplex_main() { … output = decision(safetyCtrl, &SHM->non-core, &SHM->F); } simplex_ main() { … sendControl(output); … } /***SafeFlowAnnot: assert(safe(output)) ***/ Step #4 Propagates to assert violation SAFEFLOW Analysis Algorithm At Work float decision (float safeControl, SHMData *noncore, Feedback *F) { if (checkSafety(F, noncore)) return noncore->control; else return safeControl; } Step #1 SHMPtrs(decision/checkSafety) noncore -- <noncore, 0> F -- <feedback, 0> /***SafeFlowAnnot: assume(safe(noncore, 0, sizeof(SHMData))) ***/ Step #2 SafeSHMPtrs(decision/checkSafety) noncore – <noncore, 0, size> Warning reported Step #3  F is unsafe incheckSafety Error reported

  19. Evaluation Implementation: As a sequence of analyses on LLVM byte code • Annotation burden • Few local annotations • Majority of annotations (15/22, 15/23 and 9/11) are initializing function annotations • Source changes only for separation of monitoring function -- Diff changes don’t reflect actual effort

  20. Evaluation II • Found two error values propagated in generic eSimplex implementation; one in IP; two in double IP early impl. • Dependency between core and non-core controller -- caused due to one of three different assumptions (or oversight!) • No data races with the unreliable controller • Non-core controller is encapsulated to write onto fixed shm field • Unmonitored read does not affect a critical value • All exploitable to violate safety requirements • Errors contained 2 false positives in IP; 2 in double IP; 6 in generic • Main reason: Control dependency on variables such as subscribedController • False positive test --Use the value flow chain and enforce that each link in the chain is safe i.e. the value is not used in the computation of a critical value • BUT, good software engineering to separate these values out of core component • Warnings are precise (modulo correct annotations) – due to language restrictions

  21. Related Work Applicability Prior Work Heavy-weight type system for confidentiality, integrity of program vars Secure Information Flow E.g. JIF, Volpano et al Best-effort (unsound) bug detection Metal Specifications Type qualifiers useful in propagation of attributes; No monitoring; False positives Approach practical for embedded systems CQual Run-time detection using tags taintPerl • In contrast, our analysis exploits domain information to (1) have few false positives; (2) use light-weight annotations; and (3) incur no run-time overhead

  22. Safe inter-component interaction Property to be verified Synch. Bugs; Compatible interfaces The difficult bugs Run-time monitoring of non-core values What we verify? Summary • Static analysis is a very attractive tool for embedded system architecture conformance such as core functionality isolation • BUT, pick an analyzable and specifiable property • Simple annotations provides rigor to explicitly identify unsafe value flow to core • The errors caught from such an approach are subtle, unexpected, and potentially catastrophic Restricted shared memory pointers + annotations Restrictions Imposed

  23. Future Directions • Extend to systems, which contain multiple criticality levels • Annotations can specify more properties about monitors • Value flow through other channels, particularly the environment – e.g. files, env variables • Extend analyses to other architectural properties • E.g. enforcing that all feedback values are Kalman filtered • Annotation language and analysis can be reused: filtering functions and annotations with corresponding predicates

  24. Thank You!

  25. Error #2 Programmer unknowingly accesses non-core data OR Programmer’s assumptions are wrong AND Non-core data affects critical data in core component Sources of Implementation Errors: Summary Source: Four laboratory control systems Error #1 Var not monitored along some path Non-core data Monitored shared vars Feedback Non-core Control • Unmonitored shared vars • Why not? • Programmer simply missed it! • Programmer assumes this part of shm does not contain non-core value • Programmer assumes that var does not affect critical data in the core component Reference

  26. SAFEFLOW Analysis Algorithm • Find shared memory initializations and all shared memory pointers in each function – SHMPtrs(F) • Discover initializing functions • Interprocedurally propagate the shared memory pointers and the <SHM, offset> that they refer to • In each function Enforce language restrictions on shared memory pointers • Detect unsafe type-casts or array indexing Process assume annotations and identify unsafe shared memory pointer dereferences [Does <SHM, offset> belong to SafeSet<SHM, offset>?] • Propagate unsafe values and discover any assert violations • Use value flow graphs (similar to ESP or type-qualifier inference in CQual) • Implementation-- On LLVM byte code as a series interprocedural passes: • ValueFlow Analysis followed by SafeFlow analyses

  27. Alternate Solution: Safe SHM Library Goal: A safe set of programming primitives for value propagation to ease programmer effort Pros: No annotations Cons: More restructuring; Initialize shared memory size SHMStruct *theSHM; float feedback = readFeedback(); theSHM = (SHMStruct *) libshminit(sizeof(SHMStruct)); register_monitor((void *) theSHM, &valMonitor, sizeof(theSHM->fld0)); double ctrl; if (readSHMVal((void *) the SHM, sizeof(theSHM->fld0), &ctrl, (void *) &feedback)) { // ctrl is safe } else { ctrl = SAFE_VALUE; } sendControl(ctrl); Register int monitor for offset Read value in shm at offset

More Related