27
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

Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 1: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 2: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 3: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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)

Page 4: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 5: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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]

Page 6: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 7: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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); }}

Page 8: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 9: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 10: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 11: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 12: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 13: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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)

Page 14: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 15: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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)) ***/

Page 16: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 17: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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); }}

Page 18: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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);

}

Page 19: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 20: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 21: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 22: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 23: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 24: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

24

Thank You!

Page 25: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 26: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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

Page 27: Static Analysis to Enforce Safe Value Flow in Embedded Control Systems

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