···6677// talk about the standard unix abstractions
8899-In mainstream operating systems, security policy is enforced at runtime by a
1010-omnicient and all powerful kernel.
99+In mainstream operating systems, a
1010+omnicient and all-powerful kernel enforces security policy at runtime.
1111// what am i trying to say here.
1212It acts as the bodyguard, holding all i/o and data protected unless the
1313requesting party has the authorization to access some resource. This tight
1414-coupling of security policy and access mechanisms works well since any accesses
1515-must be done through the kernel, so why not perform security checks right
1616-along-side an access. However
1414+coupling of security policy and access mechanisms works well since any access
1515+must be done through the kernel, so why not perform security checks
1616+alongside accesses? However,
1717the enforcement of security policy starts getting complicated when we try
1818-to seperate the access mechanisms from the kernel. This notion arises
1818+to separate the access mechanisms from the kernel. This problem arises
1919in a certain class of operating systems.
20202121-== Data Centric Operating Systems
2121+== Data-Centric Operating Systems
22222323-Data centric operating systems are defined by two principles @twizzler:
2323+Data-centric operating systems are defined by two principles @twizzler:
24242525- + Provide direct, kernel-free, access to data.
2525+ + They provide direct, kernel-free, access to data.
26262727- + A notion of pointers that are tied to the data they represent.
2727+ + They have a notion of pointers that are tied to the data they represent.
28282929Mainstream operating systems fail to classify as data-centric operating
3030systems, as they rely on the kernel for all data access, and use virtualized
3131pointers per process to represent underlying data. The benefit of this "class"
3232of operating systems comes from the low overhead for data manipulation, due to the lack
3333-of kernel involvement. However our previous security model fails to operate
3434-here as, by defenition, the kernel cannot be infront of accesses to data. So,
3333+of kernel involvement. However, the mainstream security model fails to operate
3434+here as, by definition, the kernel cannot be in front of access to data. So,
3535something new must be investigated.
36363737== Capability Based Security Systems
···4141//
4242// how they are different from earlier thingies
43434444-Capability based security systems have a rich history in research, and offer
4545-an alternative approach to security, in opposition to the ACL's of prevalent OS's @linux_security.
4646-Boiled down, a capability is a token of authority, holding at mininum some
4444+Capability-based security systems have a rich history in research, and offer
4545+an alternative approach to security, in opposition to the Access Control Lists of prevalent OS's @linux_security.
4646+Boiled down, a capability is a token of authority, holding at minimum some
4747permissions and a unique identifier to which "thing" those permissions apply
4848-to @cap-book. This simple approach of having a "token", allows for a large seperation
4848+to @cap-book. This simple approach of having a "token", allows for a separation
4949of the kernel's involvement in the creation and management of security policy.
5050-In a well designed system, as we see in @twizsec and described later, allows for
5050+In a well-designed system, as we see in @twizsec and described later, this allows
5151users to completely create and manage security policy while the kernel is left to enforce
5252-it. This paradigm allows for the kernel-free access of data, while also guaranteeing
5252+it. This paradigm permits kernel-free access of data, while also guaranteeing
5353security.
54545555···5959In this thesis, I detail the fundamentals of security in the Twizzler
6060operating system, and discuss how I implement and refine some of the high
6161level ideas described in Twizzler @twizzler and an early draft of a Twizzler security
6262-paper @twizsec. Additionally we evaluate these systems inside kernel and user space,
6363-with comparsions to micro-benchmarks done with an older version of twizzler.
6262+paper @twizsec. Additionally, we evaluate these systems inside kernel and user space, using
6363+Alice/Bob scenarios and microbenchmarks.
6464Code can be found in this
6565#link("https://github.com/twizzler-operating-system/twizzler/issues/268")[Github
6666tracking issue].
+35-50
2-keypair.typ
···44#mol-chapter("Key Pairs")
5566// what are keypair objects ?
77-Key pairs in Twizzler are the representation of the cryptographic signing schemes
88-used to create a signed capability, discussed in 3.1.
99-We design the keypair objects to be agnostic towards what cryptographic
1010-schemes are underneath, allowing for the underlying algorithm to be changed
1111-@twizzler. The keys themselves are stored inside of objects, allowing for
1212-persistent or volatile storage depending on object specification, and
1313-allows for keys themselves to be treated as any other object and have security
1414-policy applied to them. This allows for powerful primitives and rich
1515-expressiveness for describing secruity policy, while also being flexible enough
1616-to make basic policy easy.
77+Key pairs in Twizzler are representation of the cryptographic signing
88+schemes used to create a signed capability, as discussed in 3.1. We design
99+the keypair objects to be agnostic towards the underlying scheme to allow for
1010+multiple schemes, as described in @twizzler. This also helps with backwards
1111+compatibilty when adding new, more secure schemes, in the future. The keys
1212+are stored inside of objects, allowing for persistent or volatile
1313+storage depending on object specification, and allows for keys themselves to
1414+be treated as any other object and have security policy applied to them. This
1515+allows for powerful primitives and rich expressiveness for describing secruity
1616+policy, while also being intuitive enough to construct basic policy easily.
17171818-Suppose for instance we have Alice on Twizzler, and all users on twizzler
1919-have a "user-root" keypair that allows for them to create an arbitrary number of
2020-objects. Also suppose that access to this user-root keypair is protected by some
2121-login program, where only alice can log in. This now means that Alice now
2222-can create new keypairs, protected by her user-root keypair. Since all her
2323-new keypairs originate from her original user-root keypair, only she can access
2424-the keys required to create new signatures of hers. It forms an elegant solution for
2525-capability creation without the involvement of the kernel.
2626-2727-2828-2929-3030-// how are they represented in twizzler ?
31183219== Abstraction
33203421The `SigningKey` struct is a fixed length byte array with a length field
3522and an enum specifying what algorithm that key should be interpreted as.
3636-Currently we use the Elliptic Curve Digital Signature Algorithm (ECDSA)
3737-@ecdsa to sign capabilities and verify them, but the simplistic dat
3838-arepresentation allows for any arbitrary alogrithm to be used as long as
3939-the key can be represented as bytes.
2323+Currently we use the Elliptic Curve Digital Signature Algorithm (ECDSA) @ecdsa
2424+to sign capabilities and verify them, but the simplistic data representation
2525+allows for any arbitrary alogrithm to be used as long as the key can be
2626+represented as bytes.
40274141-Additionally this specification allows
4242-for backward compatibility, allowing for an outdated signing scheme to be used in
4343-support of older programs / files. An existing drawback for backward compatibility is the
4444-maximum size of the buffer we store the key in. Currently we set the maximum size as 256 bytes,
4545-meaning if a future cryptographic signing scheme was to be found with a private key size
4646-larger than 256 bytes, we would have to drop backwards compatibility. Sure this
4747-can be prevented by setting the maximum size to something larger, but that a tradeoff
4848-between possible cryptographic schemes vs the real on-disk cost of larger buffers.
2828+Additionally this specification allows for backward compatibility, allowing
2929+for an outdated signing scheme to be used in support of older programs /
3030+files. An existing drawback for backward compatibility is the maximum size
3131+of the buffer we store the key in. Currently we set the maximum size as 256
3232+bytes, meaning if a future cryptographic signing scheme was to be created with
3333+a key size larger than 256 bytes, we would have to drop backwards
3434+compatibility. Sure this can be prevented now by setting the maximum size to
3535+something larger, but thats a tradeoff between possible cryptographic schemes
3636+vs the real on-disk cost of larger buffers.
49375038== Compartmentalization
5139// how they can be used to sign multiple objects (compartmentalization)
52405341To create an object in twizzler, you specify the id of a verifying key
5442object so the kernel knows which key to use to verify any
5555-capabilities permitting access to the object. You can also specify
5656-default protections for an object or create a capability with the signing
5757-key and any desired permissions.
5858-5959-The neat thing about this design is that you can use a single keypair in-order to use
6060-any arbitrary amount of objects. An example could be a colletion of objects holding files for a class, and grouping all of them
6161-under the same key. In short, having this flexibility allows for a significant debloating
6262-of the filesystem, comparted to creating a new keypair for every single object.
4343+capabilities permitting access to the object. Since keys are represented as objects
4444+in twizzler, security policy applies on them as well, creating satisfying
4545+solutions in regards to key management.
63466464-In planned future work , as we talk more about in
6565-we can investiage the This results in the possibility of finegrained
6666-access control to semantic groupings of objects.
6767-// what the fuck am i trying to say
4747+Suppose for instance we have Alice on Twizzler, and all users on twizzler have
4848+a "user-root" keypair that allows for them to create an arbitrary number of
4949+objects. Also suppose that access to this user-root keypair is protected by
5050+some login program, where only alice can log in. This means that Alice
5151+can create new keypair objects from her user-root keypair. Since all
5252+*her* new keypairs originate from *her* original user-root keypair, only *she* can
5353+access the keys required to create new signatures allowing permissions into
5454+*her* objects. It forms an elegant solution for key management without
5555+the involvement of the kernel.
68566969-// all it does is make creation easier, since you only need one pair, it doesnt
7070-// restrict capabilities or whatever. It's just a benefit since we dont have to worry
7171-// about managing a keypair for every single object
72577358#load-bib(read("refs.bib"))
+28-17
3-cap.typ
···66// define a capability
77Capabilities are the atomic unit of security in Twizzler, acting as tokens of
88protections granted to a process, allowing it to access some object in the ways
99-it describes. A Capability is built up of the following fields.
99+it describes. Colloquially a capability is defined as permissions and
1010+a unique object to which those permissions apply, but in Twizzler we add
1111+the signature component to allow the kernel to validate that the security policy was created by an authorized party.
1212+1313+Thus, a Capability is represented as follows:
101411151216```rust
···1721 flags: CapFlags, // Cryptographic configuration for capability validation.
1822 gates: Gates, // Additional constraints on when this capability can be used.
1923 revocation: Revoc, // Specifies when this capability is invalid, i.e. expiration.
2020- sig: Signature, // The signature inside the capability.
2424+ sig: Signature, // The signature.
2125}
2226```
23272428//
2529== Signature
2626-The signature inside is what determines the validity of this capability. The
3030+The signature is what determines the validity of the capability. The
2731only possible signer of some capability is who ever has permissions to the
2828-signing key object, or the kernel. In this way, if the signer decides to
2929-make the signing key private to them, no other entity can administer this
3030-signature for this capability. The signature is built up of a array with
3232+signing key object, or the kernel itself. The signature is built up of a array with
3133a maximum length and a enum representing what type of cryptographic scheme
3234was used to create it; quite similar to the keys mentioned previously.
3333-The message being signed to form the signature is the bytes of each of the
3434-fields inside the capability being hashed. There is support for multiple
3535-hashing algorithms as described in 3.1.
3636-3535+The fields of the capability are serialized and hashed to form the message that gets signed,
3636+and then stored in the signature field. Currently we support Blake3 and
3737+Sha256 as hashing algorithms.
37383839// what do i want to talk about regarding signatures?
39404041== Gates
4242+Gates act as a limited entry point into objects. If a capability has a non-trivial gate,
4343+which is made up of an offset field, and a length field, the kernel will read that and ensure
4444+that any memory accesses into that object are within the gate bounds. The original Twizzler
4545+paper @twizzler describes gates as a way to perform IPC, and calls between distinct programs,
4646+but in the context of this thesis it is sufficient to think of them as a region of allowed
4747+memory access.
41484249== Flags
4343-Currently flags in capabilities are used to specify which hashing algorithm to use in order
4444-to form a message to be signed. We allow for multiple algorithms to be used in order to
4545-allow for backwards capability when newer, more efficient hashing algorithms are created.
4646-4747-There is also plenty of space left in the bitmap, allowing for future work to develop more
4848-expressive ways of using capabilities, such as planned future work to implement information
4949-flow control into the twizzler security system.
5050+Currently, flags in capabilities are used to specify which hashing algorithm to use to form a message to be signed. We allow for multiple algorithms to be used to
5151+allow for backward capability when newer, more efficient hashing algorithms are created.
50525353+The flags inside a capability is a bitmask providing information about distinct feautures
5454+of that capability. Currently we only use them to mark what hashing algorithm was used to
5555+form the message for the signature, but there's plenty of bits left to use.
5656+We hope for future work to develop more expressive ways of using capabilities, i.e. Decentralized Information Flow Control, as specified in
5757+6.1.
515852595360#load-bib(read("refs.bib"))
6161+6262+6363+6464+
+36-22
4-secctx.typ
···2233#mol-chapter("Security Contexts")
4455-Security Contexts are objects that store capabilites, which processes can attach onto, inherting the
66-permissions granted by the capabilities that reside inside.
77-88-== Enforcement
99-1010-The enforcement of security policy in Twizzler happens on page fault when trying to access
1111-a new object @twizzler. Then the kernel inspects the security contexts attached to
1212-the accessing proccess, looking up what capabilities those contexts hold and if they are applicable
1313-to the object being accessed. The original twizzler paper @twizzler, and the following security paper
1414-go into more detail about the philosophy behind why enforcement works this way, such as the
1515-performance benefits of letting programs access objects directly without kernel involvement, etc.
1616-1717-1818-55+Security Contexts are objects that processes attach to in-order to inherit the
66+permissions inside the context. The contexts store capabilities, allowing for userspace
77+programs to add capabilities to contexts, and kernel space to efficiently search
88+through them to determie whether a process has the permissions to perform a memory access.
1992010== Base
21112212Since security contexts can be interacted with by the kernel and userspace, there needs to
2323-be a consistent defenition that both parties can adhere to, which we define. Objects in twizzler
1313+be a consistent definition that both parties can adhere to, which we define. Objects in Twizzler
2414have a notion of a `Base` which defines an arbitrary block of data at the "bottom" of an object
2515that is represented as a type in rust. We define the `Base` for a security context as follows:
2616···35253626=== Map
3727The map holds positions to Capabilities relevant to some target object, which
3838-the relevant security context implementations for kernel and userspaces to
2828+the relevant security context implementations for kernel and userspace to
3929parse security context objects. Implicitly, the kernel uses
4030this map for lookup while the user interacts with this map to indicate the insertion, removal, or modification of
4131a capability.
···4333=== Masks
4434Masks act as a restraint on the permissions this context can provide for some targeted object.
4535This allows for more expressive security policy, such as being able to quickly restrict
4646-permissions for an object, without having to remove a capability, and recreating one with the
3636+permissions for an object, without having to remove a capability and recreating one with the
4737dersired restricted permissions.
48384939The global mask is quite similar to the masks mentioned above, except that it operates on
···5141// what now
5242//
5343=== Flags
5454-5555-5656-4444+Flags is a bitmap allowing for a Security Context to have different properties. Currently, there
4545+is only one value, UNDETACHABLE, marking the security context as a jail of sorts, as
4646+once a process attaches to it, it won't be able to detach. This acts as a way to
4747+limit the transfer of information if a thread attaches to a sensitive object. Once a thread
4848+attaches to such a context, it is forced to end its execution with the objects that context grants
4949+permission to. We also plan to utilize these flags in future works, as described in 6.1.
575058515252+== Enforcement
59536060-// on disk storage for security contexts for efficient lookup
5454+All enforcement happens inside the kernel, which has a seperate view into Security Contexts
5555+than userspace. The kernel keeps track of all security contexts that threads in Twizzler
5656+attach to, instantiating a cache inside each one. Additionally, a thread can attach
5757+to multiple security contexts, but can only utilize the permissions granted by one unless
5858+they switch @twizzler. To manage these threads, the kernel assigns a Security Context Manager,
5959+which holds onto security context references that a thread has.
61606161+The enforcement of security policy in Twizzler happens on page fault when trying to access
6262+a new object @twizzler. Upon fault, the kernel inspects the target object and identifies the
6363+default permissnons of that object. Then the kernel checks if the currently active
6464+security context for the accessing thread has either cached or capabilities that provide
6565+permissions. If default permissions + the active context permissions arent enough to
6666+permit the access, the kernel then checks each of the inactive contexts to see if they
6767+have any relevant permissions. If there exists such permissions, then the kernel will
6868+switch the active context of that process to the previously inactive context where the permission
6969+was found. If it fails all of these, then the kernel terminates the process, citing inadequate
7070+permissions.
62716363-// what else is special about security contexts?
7272+Since the security context can have a mask per object, while also having a global_mask to
7373+the protections it can grant, the kernel also takes this into account while determining if
7474+a process has the permissions for access.
64757676+The original Twizzler paper @twizzler, and the following security paper
7777+go into more detail about the philosophy behind why enforcement works this way, such as the
7878+performance benefits of letting programs access objects directly without kernel involvement, etc.
65796680#load-bib(read("refs.bib"))
+110-5
5-results.typ
···11#import "template.typ": *
22+33+#import "@preview/unify:0.7.1"
24#mol-chapter("Results")
3546// benchmarking
···1315//
1416// take measurements without security checks too so you can see the security overhead
1517//
1616-All testing was done in QEMU, with a Ryzen 5 2600 processor.
17181919+== Validation
18201919-== Validation
2121+The first test is a basic scenario as a check to make sure the system is behaving as intended, and
2222+a more expressive test to demonstrate the flexibility of the model. Eventually, I intend to work with
2323+my advisor and peers to form a proof of correctness for the security model, as well
2424+as empirical testing to demonstrate its rigidity.
20252126=== Basic
2727+TBA
2828+== Expressive
2929+TBA
223023312424-=== Expressive
3232+== Micro Benchmarks
3333+Additionally, we have microbenchmarks of core security operations in Twizzler. All
3434+benchmarks were run with a Ryzen 5 2600, with Twizzler virtualized in QEMU. Unfortunately
3535+I ran out of time to perform benchmarks on bare metal, but they should be the same, if
3636+not more, performant.
25373838+=== Kernel
26392727-== Micro Benchmarks
4040+There a couple of things we benchmark inside the kernel, including core cryptographic
4141+operations like signature generation and verification, as well as the total time it takes
4242+to verify a capability.
4343+#figure(
4444+table(
4545+ columns: (auto, auto),
4646+ inset: 10pt,
4747+ align: center,
4848+ table.header(
4949+ [Benchmark], [Time]
5050+ ),
5151+ [
5252+ Hashing (Sha256)
5353+ ],
5454+ [
5555+ 267.86 ns $plus.minus 163$ ns
5656+ ],
5757+ [
5858+ Hashing (Blake3)
5959+ ],
6060+ [
6161+ 125.99 ns $plus.minus 117$ ns
6262+ ],
6363+ [
6464+ Signature Generation (ECDSA)
6565+ ],
6666+ [
6767+ 199.90 $\u{00B5}s plus.minus 9.45 \u{00B5}s$
6868+ ],
28692929-=== Kernel
7070+ [
7171+ Signature Verification (ECDSA)
7272+ ],
7373+ [
7474+ 342.20 $\u{00B5}s plus.minus 6.28 \u{00B5}s$
7575+ ] ,
7676+ [
7777+ Capability Verification (ECDSA, Blake3)
7878+ ],
7979+ [
8080+ 343.59 $\u{00B5}s plus.minus 5.32 \u{00B5}s$
8181+ ]
8282+),
8383+caption: [Collection of Kernel Benchmarking Results]
8484+)
30858686+We see that signatures are vastly more expensive than hashing, on an order
8787+of $10^3$, meaning that your choice of hashing algorithm doesn't affect the
8888+total time taken for the verification of a capability. It's also important to
8989+note that this cost of verifying a capability for access is done on the first-page fault, then the kernel uses caching to store the granted permissions and
9090+provides those on subsequent page faults into that object. In the future, I hope
9191+to measure the difference between a cached and uncached verification. Secondly,
9292+we only measure verification inside kernel space; as discussed in section 3,
9393+capability creation only takes place in user space.
31943295=== UserSpace
9696+9797+In userspace, we benchmark keypair and capability creation, as these operations are core to
9898+creating a security policy.
9999+100100+101101+#figure(
102102+table(
103103+ columns: (auto, auto),
104104+ inset: 10pt,
105105+ align: center,
106106+ table.header(
107107+ [Benchmark], [Time]
108108+ ),
109109+ [
110110+ Capability Creation
111111+ ],
112112+ [
113113+ 347.97 $\u{00B5}s plus.minus 5.78 \u{00B5}s$
114114+ ],
115115+ [
116116+ Keypair Objects Creation
117117+ ],
118118+ [
119119+ 651.69$\u{00B5}s plus.minus 187.90 \u{00B5}s$
120120+ ],
121121+ [
122122+ Security Context Creation
123123+ ],
124124+ [
125125+ 282.10$\u{00B5}s plus.minus 119.90 \u{00B5}s$
126126+ ],
127127+),
128128+caption: [Collection of UserSpace Benchmarking Results]
129129+)
130130+131131+Almost all the time spent in creating a capability is the cryptographic operations used
132132+to form its signature, which is why it's in the same ballpark as the signature creation we saw earlier.
133133+134134+The high standard deviation in Keypair objects and Security context creation happens from the
135135+unpredictable time it takes for the kernel to create an object on disk. The reason keypairs
136136+are almost 2x more expensive since they create two separate objects, one for the signing key,
137137+and one for the verifying key.
+20-1
6-conclusion.typ
···2233#mol-chapter("Conclusion")
4455+In short we provide a general overview of the critical security
66+components for security system in Twizzler, along with
77+implementation details and desgin descisions. The evaluation programs show how
88+security policy can be expressed and verifies that the kernel is enforcing as
99+programmed. Lastly we go over microbenchmarks to show and explain the cost of these operations.
1010+1111+512== Future Works
613714In the future I hope to take the primitives created during my thesis, and apply them towards
88-the implementation of Decentralized Information Flow Control, as described in
1515+the implementation of Decentralized Information Flow Control, as described in @flume, into
1616+the Twizzler security model. Additionally I would love to see how the current security model
1717+evolves once we start adding distributed computing support to Twizzler, as described in
1818+the orignal paper @twizzler.
1919+2020+2121+== Acknowledgements
2222+2323+I couldn't have done the work for this thesis and for Twizzler if it wasn't for the
2424+support I've recieved from my advisor Owen Arden and my technical mentor Daniel Bittman! I
2525+owe both of you so much, not just for the class credit but also for how much I've learned in
2626+this endeavor. Thanks guys!
2727+92810291130#load-bib(read("refs.bib"))
+2-2
template.typ
···9898 align(alignment.left, [
9999 #set par(first-line-indent: 0em)
100100101101- *Date of the public defence:*
101101+ // *Date of the public defence:*
102102103103- _#defence-date _
103103+ // _#defence-date _
104104105105 #colbreak()
106106
thesis.pdf
This is a binary file and will not be displayed.
+10-3
thesis.typ
···2424)
25252626#mol-abstract[
2727- whatevea
2828- lowkey not even sure what to write
2929- ]
2727+ Traditional operating systems permit data access through the kernel, applying
2828+ security policy as a part of that pipeline. The Twizzler operating system
2929+ flips that relationship on its head, focusing on an approach where data
3030+ access is a first-class citizen, getting rid of the kernel as a middleman. With
3131+ this data-centric approach, it requires us to rethink how security policy
3232+ interacts with users and the kernel. In this thesis, I present the design and
3333+ implementation of core security primitives in Twizzler. Then I evaluate the
3434+ security model with a basic and advanced scenario, as well as microbenchmarks
3535+ of core security operations. Lastly, I discuss future work built off this
3636+ thesis, such as the incorporation of Decentralized Information Flow Control.]
303731383239