Upload
tashya-palmer
View
36
Download
2
Embed Size (px)
DESCRIPTION
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. - PowerPoint PPT Presentation
Citation preview
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
Core cont.Core subsyste
m
Run-timemonitor
feedback
control
Core subsystem
• Simple, well-tested components
• Purpose: Safety
Non-core subsystem
• Complex and relatively untested
• Performance, user-interfaces, optional features
Emerging Architectural Principle: Isolation of core functionality from non-core subsystem failures
3
Architecture ImplementationAn Implementation of the Simplex Architecture
Non-core
Core
SHM
Safe Cont.
Monitor
feedback
feedback
control
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
Non-core
Core
SHM
Safe Cont.
feedback
feedback
control
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
Monitor
5
Monitoring Value Errors in ControlValue 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 only use non-core data (run-time monitor); should not depend on it [Ding and Sha]
6
Background: Isolating the Core Component
Non-core
Core
SHM
Safe Cont.
feedback
feedback
control
Platform
Monitor
Memory Safety: Memory errors such as dangling pointers can overwrite and corrupt the core component
• Prior Work: Control-C (SAFECode), CCured
corrupt
Resource Usage: Guaranteeing a set of logical system resources to the core component
• System call monitoring; Real-time virtual machines
hogging
7
Monitoring function
Implementation of Value Flow
SHM
Feedback
Non-coreControl
Example: Simplex
Non-core
Feedback
ControlOutput
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); }}
8
Implementation Errors Isimplex_ 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-coreControl
Non-core
Feedback
ControlOutput
1. Unmonitored non-core value:
SHM->noncore unmonitored along false path
9
Implementation Errors IIsimplex_ 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-coreControl
Example: Simplex
Non-core
Feedback
ControlOutput
2. Hidden Dependencies:
SHM->F unknowingly dereferenced
10
Implementation Errors III
SHM
Feedback
Non-coreControl
Example: Simplex
Non-core
Feedback
ControlOutput
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); }}
Reference
3. Wrong Assumptions:
E.g. Reference will not be corrupted by non-core component
11
Assumptions and Goals
Required Assumptions
The run-time monitor for the non-core values is correct!
Communication through shared memory only
Performance critical systems
More challenging scenario
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
12
Contributions and LimitationsAnnotation 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 Annotationsimplex_ 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))) ***/
simplex_ main()simplex_ main() { { initializeSHMinitializeSHM();(); while (1) {while (1) { readFeedbackreadFeedback(F);(F); publishFeedbackpublishFeedback(F);(F); safetyCtrl = safetyCtrl = safety_controlsafety_control(F);(F); unlockSHMunlockSHM();(); pausepause();(); lockSHMlockSHM();(); output = decision(safetyCtrl, &SHM->non-core, &SHM->F); sendControlsendControl(output);(output); }}}}
Use the assume annotation to specify the safely accessible shared memory locationsSimple, local annotation
15
assert Annotationsimplex_ 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); }}
Assert annotation placed before critical data such as control outputs sent to the plant or argument of system calls such as kill
/***SafeFlowAnnot: assert(safe(output)) ***/
16
Restrictions on Shared Memory Usage
1. Shared memory not deallocated until end of main()
2. Pointers to shared memory Cannot be cast to incompatible types
Address cannot be taken
3. Arrays in shared memory Indices within array bounds
Loop bounds affine w.r.t size of array and loop index variables or vice versa
Enforce shared memory pointers not aliased through memory
No dangling pointers to shared memory
17
Shared Memory InitializationinitializeSHM(size_t size)
{ void *shmStart; /* Initialize shared memory */ shmid = shmget(SHMKEY, size, flags); shmStart = shmat(shmid, 0, 0); feedback = (SHMData *) shmStart; noncore = feedback + 1;
}
Language restrictions not applied to initialization function Unix shared memory initialization is untyped (needs downcasts) Arrays in shared memory need to be made explicit
simplex_ main()simplex_ main() { { initializeSHM(); while (1) {while (1) { readFeedbackreadFeedback(F);(F); publishFeedbackpublishFeedback(F);(F); safetyCtrl = safetyCtrl = safety_controlsafety_control(F);(F); unlockSHMunlockSHM();(); pausepause();(); lockSHMlockSHM();(); output = output = decisiondecision(safetyCtrl, (safetyCtrl, &SHM->non-core, &SHM->F);&SHM->non-core, &SHM->F); sendControlsendControl(output);(output); }}}}
/***SafeFlow Annotation: post-condition assume(non-core(feedback)) assume(non-core(noncore)) assume(size(feedback) = sizeof(SHMData)) assume(size(noncore) = sizeof(SHMData)) ***/
/***SafeFlow Annotation assume(shminit); ***/
Initialization Function 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); }}
18
SAFEFLOW Analysis Algorithm At Workfloat decision (float safeControl, SHMData *noncore, Feedback *F)
{ if (checkSafety(F, noncore)) return noncore->control; else return safeControl;}
/***SafeFlowAnnot: assume(safe(noncore, 0, sizeof(SHMData))) ***/
Step #1SHMPtrs(decision/checkSafety)noncore -- <noncore, 0> F -- <feedback, 0>
Step #2SafeSHMPtrs(decision/checkSafety)noncore – <noncore, 0, size>
Step #3 F is unsafe in checkSafety
Warningreported
ErrorreportedStep #4
Propagates to assert violation
simplex_ main() { …
sendControl(output); …}
/***SafeFlowAnnot: assert(safe(output)) ***/
Simplex_main() {
…
output = decision(safetyCtrl,
&SHM->non-core, &SHM->F);
}
19
Evaluation
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
System LOC
(size)
LOC
(core)
Source changes
Annots Errors Warnings
IP 7079 820 86 (7) 11 1 7
Generic 8057 1020 0 22 2 7
Double IP
>7188 929 88 (7) 23 2 8
Implementation: As a sequence of analyses on LLVM byte code
20
Evaluation IIFound 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
Prior Work ApplicabilitySecure Information FlowE.g. JIF, Volpano et al
Heavy-weight type system for confidentiality, integrity of program vars
Metal Specifications Best-effort (unsound) bug detection
taintPerl Run-time detection using tags
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
Approach practical for embedded systems
CQualType qualifiers useful in propagation of attributes; No monitoring; False positives
22
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
Property to be verified
The difficult bugs
What we verify?
Safe inter-component interactionSynch. Bugs; Compatible interfacesRun-time monitoring of non-core values
Restrictions Imposed Restricted shared memory pointers + annotations
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
Sources of Implementation Errors: Summary
Non-core data
Feedback
Non-coreControl
Reference
Monitored shared vars
Unmonitored shared varsWhy 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
Source: Four laboratory control systems
Error #1Var not monitored along some path
Programmer’s assumptions are wrong
Error #2Programmer unknowingly accesses non-core dataOR
AND
Non-core data affects critical data in core component
26
SAFEFLOW Analysis AlgorithmFind 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 functionEnforce language restrictions on shared memory pointers
• Detect unsafe type-casts or array indexingProcess 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;
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);
Initialize shared
memory size
Register int monitor for
offset
Read value in shm at
offset