cache_security.html 5.73 KB
<html>

<head>
        <title>SK Cache Gatekeeping</title>
</head>
<body>

<center>
<h1>SK Cache Gatekeeping</h1>
</center>

<h2>Overview</h2>

The cache handling on SK entrance and exit plays an essential role in
the overall security scheme. Without proper cache handling an attacker
could take control of the secure-mode execution, which would break our
fundamental security assumptions.
<p>
On the flip-side, the cache management for entry and exit is the
costliest portion of SK entry and exit. This document will describe the
rational behind measures taken to insure the cache cannot be used
to compromise the system. Tradeoffs may then be considered between
security risk vs. entry/exit cpu cost to determine exactly what is
implemented.


<h2>Cache Gatekeeping</h2>

The lists below summarize the cache gatekeeping under consideration.

<p>
<b>I-Cache on SK Entry</b><br>
<ul>
    <li><i>Security Risk:</i> Running rogue code. <p>
        An attacker could fill the icache with arbitrary code using
	the cache "fill" instruction, then use cache "index-store-tag"
	to provide an internal sram address for the code. Once running
	in the SK, some future fetch from icache would result in the
	arbitrary code being executed, and this code could dump internal
	sram data to dram. (we do eventually switch to
	cached execution upon NMI entrance to SK).
    <li><i>Resolution:</i>
        Issue cache "index-store-tag" (with C0_TAGLO zero'd) over every 
	icache line to insure all internal code is initially loaded
	from memory instead of the cache.
    <li><i>CPU cost:</i>
        ~86usec @ 62.5MHz sysclk.
</ul>
<p>
<b>D-Cache on SK Entry</b><br>
<ul>
    <li><i>Security Risk:</i> Running rogue code. <p>
        An attacker could fill dcache lines with arbitrary data (which
        could be executable code) by first loading the data from main
	memory to cache based on index, then using cache "index-store-tag"
	to make the data appear to reside in internal sram. This data
	may then be used to replace data the SK relies on, or to place
	a code snippet into the execution path. The latter could be
	accomplished by supplying a physical tag that would cause the
	line to be written-back to an executable area. (i.e., some
	internal load causing a cache miss would force the write-back
	to an address arbitrarily chosen by the attacker).
    <li><i>Resolution:</i>
        Over every dcache line, check if the line is valid, and then if
	the associated tag determines an internal address. If so, zero
	the C0_TAGLO register and use cache "index-store-tag" to
	invalidate the line.
    <li><i>CPU cost:</i>
        ~260usec @ 62.5MHz sysclk. 
</ul>
<p>
<b>I-Cache on SK Exit</b><br>
<ul>
    <li><i>Security Risk:</i> Plaintext visible SK code. <p>
        If snippets of SK code are left in the icache an attacker could
	obtain these in plaintext form. This can be accomplished by
	using cache "index-load-tag" to determine the code location
	internally, cache "index-store-tag" to set the tag to reference
	dram, then cache "hit-write-back" to cause the line to be
	written to where the tag points (dram).
    <li><i>Resolution:</i>
        Issue cache "fill" to every icache line to overwrite sk code
	with zeros, then "index-invalidate" over every icache line.
	<p>
	<i>For now we have decided not to perform this step.</i>
	<p>
    <li><i>CPU cost:</i>
        ~86usec @ 62.5MHz sysclk.
</ul>
<p>
<b>D-Cache on SK Exit</b><br>
<ul>
    <li><i>Security Risk:</i> Sensitive internal data visible. <p>
        The security risk is that any sensitive data in the dcache
	would be readable once secure mode is exited (by using
	cache "index-store-tag" to tag the line to dram, then
	cache "hit-write-back-invalidate" to store to dram).
    <li><i>Resolution:</i>
        In this case, we cannot simply insure all the dcache
	lines are invalidated, since the cache "index-store-tag"
	could always be used to set the state back to dirty.
	<p>
	Since we need to srub (i.e., zero) the iram whenever
	the application has iram access, and since all valid internal
	dram cache lines must be written back in case they hold
	peristant state, the iram scrub is used to force a writeback
	of all dcache lines. This works because the chunk of iram
	that must be scrubbed is larger than the dcache.
	<p>
	So, iram is first written with zeros, then the entire
	dcache is "index-write-back-invalidate" to writeback
	the iram zeros and invalidate the cache lines.
	<p>
	Just for completeness, here is another method of resolving
	this issue (WE DID NOT USE THIS METHOD!).  harcode kseg1
	addresses for all sensitive (key) data used in the SK (to
	insure it does not end up in the dcache).  It is dificult to
	insure this really hides that data, however, since many api
	calls will first copy data to a cached address as part of
	setting up calls to lower-level apis. Also, there is still the
	possibility that dcache data generated during the computations
	performed that use the sensitive kseg1 data could be
	sensitive, but this mapping is dificult to predict. Here we
	would need to be careful not to slow execution too much by
	placing too much data in non-cached storage.
    <li><i>CPU cost (for both the "index-write-back-invalidate" and
        dword writes to fill the line with zeroes, over each internally
	tagged line):</i><br>
	~200usec @ 62.5MHz.
</ul>

<p>
Note that because the cost of dcache cleanup on exit is so high, we
may choose to insure this is not needed for timer handling exits.

<p>
Another bit of gatekeeping is that the C0_SR[BEV] bit cannot be set
back to point to external exception vectors until we have actually
issued the write to exit secure mode. Otherwise, and ill-timed
exception would allow arbitrary code in dram to run in secure mode.
WE DECIDED SUCH AN EXCEPTION CAN NOT REASONABLY BE CREATED, SO IGNORE
THIS ISSUE.
</body>
</html>