 Hello, everyone. My name is Fan Wu. I'm a software engineer at Microsoft. My work is code integrity both on Linux and Windows. In this talk, I'm going to talk about code integrity in Linux. Code integrity essentially is when we try to use a file, we guarantee the file is not modified by an attacker. To give some background here, my coworker Devon proposed an LSM called IP last year. The feedback from the upstream was they wanted us to try to implement the features of IP into IMA. I will present the current progress of the investigation. We will have a brief introduction to our design motivation and what is IP. Then followed by the features of IP, we added it to IMA. Then followed with the discussion. We are trying to build a security system for fixed function machines. For example, network firewall device in a data center or an IoT device like smartwatch machine. This device don't need frequent update and can be completely locked down, so we can provide a high-level security guarantee. Other than the security part, we also want to have a high-level availability, so we don't want to reboot the machine. Also, we want the failure can be easily diagnosable, such that as long as we see the lock, we know where is the problem inside the system. Finally, the hardware resources for such kind of devices are limited, like small RAM sites, which means it will incur more disk risk and may lose more tax. Here's our threat model. We want to let our system can protect the integrity of files in the user space. Specifically, we want to protect the executable binaries and configuration files. The attacker can have the access of the machine locally or remotely as a user. The attacker can also be a compromised malicious block device, which can send arbitrary malicious data to the kernel. Some attacks are out of scope. When the kernel is compromised, the security system can be just bypassed, so there's no security guarantee. Or the memory can be directly modified, then the attacker can almost run anything. Here's a brief introduction to IPE. IPE is a Linux security module, like SC Linux, up armor. It provides a policy to control the system-wide coding integrity requirement and the enforcement. It only do one thing that is coding integrity. It completely decoupled the policy and the mechanism. IPE itself only provides policy enforcement. All the actual integrity mechanisms are provided by the other kernel components. Essentially, this means what IPE do is it's just a law or denied file based on the file context that contains what kind of security or the integrity mechanism are used to protect the file. For now, IPE supports DM variety and FS variety. New mechanisms can be easily supported because IPE has a modular design. IPE also has a flexible policy syntax and the comprehensive policy control interfaces. IPE has a swapable reboot-less policy, which means we can deploy multiple different policies at the same time and switch to whatever we want to use without any reboot. IMA has a place for code integrity, but some features are missing. The highlighted are the subset of features of IPE we tried to add to IMA. Starting from here, we are going to talk about the details of the missing features of IMA. The first thing is granularity. We think the granularity for large and small units are both important. But IMA only supports file-level granularity. It has no support for whole block device, which can make the deployment process complicated. The second thing is the whole file needs to be measured before a praise. Measure here means to read the whole file content, then hash it and use that hash as the feature of the file. This will incur a very noticeable latency increase for large files because the whole file needs to be read from the disk. It cannot verify the file integrity if the file is not opened with read permission. This is essentially a system layering issue. What caused this problem is because IMA operates on the security system level, which is above the file system. To read the file content, it has to interact with the file system. So if the file is not opened with the read permission from the user space, then the IMA cannot be allowed by the file system to read the file's content. The most critical issue is IMA can be cheated by malicious block devices. There's a paper published last year detailed the actual attack. In short, if we have a very big file that cannot fit into the memory, at the measurement process, the attacker can send a good file content to the IMA, and IMA will think the file is a good file. Then, because the file cannot fit into the memory, when the user wants to use the file, it has to read the file content from the block device again. At this time, the block device can send arbitrary malicious data to the kernel, such that the user can be attacked. Again, this is because IMA is above the file system level, so it cannot do the integrity check on every disk operation. Then it's the policy syntax issue. Essentially, policy cannot make a law or deny decision on its own. For example, there's a praise rule here, and this will be applied to all files when it is used by MAP with execution permission. If the rule is applied to a file, after the policy evaluation, IMA cannot make the decision of allow or deny the use of the file. It will ask other parts of the IMA to compare the file hash against a pre-computed hash, then make the decision. This is also a result of coupling of policy and mechanism. The solution here we propose is to utilize DM variety, make IMA just like IPE to delegate the actual integrity mechanism to DM variety instead on its own. The benefit here we get is we will have a significantly smaller read latency overhead thanks to the hash tree of DM variety. Also, by using DM variety, it can also avoid IMA interacts with the file system. This is because the actual integrity protection is dedicated to the DM variety, and the DM variety is operated on the block device level, which will do the actual verification on every disk operation. We also added two new pre-type to let the policy can make the allow or deny decision in the policy. Here's the actual implementation of the DM variety support for IMA. First, we added a new security block device such that we can save some DM variety metadata, like the root hash or the signature. During the policy evaluation, IMA can make the allow or deny decision based on these metadata. Then we added two new policy conditions for DM variety. This gives the policy the ability to specify which DM variety volume is allowed to be used. Finally, we added two new appraised type, which gives the policy the ability to make the allow or deny decision. Here, the first one appraised type equals DM variety, where allow files from a DM variety volume to be used if the DM variety condition rules are satisfied. The parcel will make sure if this appraised type is used, there must be some DM variety rule conditions inside the rule. The second one appraised type equals deny will deny files if the rule condition can be satisfied. At the bottom, we give two examples of policy rules to allow files to be used from a specified DM variety. The first one will allow files to be M-mapped if it is from a signed DM variety volume. The second one will allow files to be M-mapped if the volume hash matches with the hash inside the rule condition. Then we move on to the IMA policy control limitations. The first thing is IMA has limited policy interfaces. Only one policy can be deployed. It is impossible to deploy multiple independent policies. For features like use different policies for different containers, it is hard to implement for the current IMA. The second thing is the deployed policy cannot be deleted without a reboot. Sometimes our policy need to be updated or deleted. Because IMA need to reboot the machine to delete the policy rules, it will greatly impact our availability time. It has no permissive switch. IMA doesn't have a permissive switch that is available in SELinux and IPE. This feature is extremely useful for designing and experimenting new policies. The second thing is IMA doesn't have a full control of deployed policy rules. In some cases, it will implicitly add some rules that has higher priority than the user deployed rules. This could be problematic if the implicit rules are causing the problem to the system. And because these rules cannot be deleted without changing the source code, we have to figure out the way to solve this issue. Finally, IMA uses itself to verify the integrity of the policy file, which can be affected by multiple factors like the IMA keyrings, like the extended attributes, or the block list. We think using other mechanisms will be better to verify the integrity of the policy. So the solution of our extension is we added a new kernel structure to track the deployed policy states, like the policy flex, so that we can deploy multiple different policies. We extended the security file system such that we can deploy multiple policies and manage them. We added a kernel switch to remove the implicitly deployed policy rules. We utilized the PKC7 to verify the policy integrity against the kernel trusted keyring instead of IMA's own keyrings. We introduced a permissive switch for IMA to switch to the permissive mode. Here is the actual implementation of the new control interfaces prototype for IMA. First, we created a new structure to encapsulate the policy. The encapsulation of policy won't break any existing IMA features. The structure will be used to track policy flex for each policy. Previously, IMA uses many global variables for these policy flex, but now we have multiple policies. We need to have a structure to track the different policies. We added a new policy attributes, saved them inside a new policy structure. For example, we can have some policy versions inside the policy structure such that we can prevent anti- rowback attack. Here, the anti-rowback means we can prevent all the policy overwrite the new policies. Because we have multiple policies now, we need to have a name for each policy. We extended the policy syntax such that we added a new action called policy and the new condition rules called policy name to assign each policy name. Then we changed the policy management interfaces. We created a new file inside the security file system such that we can deploy the policy by the PKC7. We also created a new folder inside the security file system so that such that the administrator can manage the policies. And because we have multiple policies now, we added a new pointer which is protected by the RCU. That will point to the policy structure currently active. We guarantee only one policy will be active at the time. Finally, we introduced the permissive switch inside the security file system such that that is protected by the memory barriers just like what is implemented in SNLinux and IPE. And here we have a demo. We will run two binaries. One is GCC, which is not inside the DRM variety of volume. One is Halloword, which is inside the DRM variety of volume. And we will try different policies and see the behavior of the system. So here we see we have mounted a DRM variety of volume inside the TEMP file system. That is TEMP IP test. Then we switch to the policy management folder inside the IMA security file system. And there's only default policy deployed. And we can see the content inside. There's no appraisal inside. So everything will be allowed to be executed. Now we will switch to a folder that contains the policy and use cat to write the policy content to the security file system node. And we can see we have deployed three policies. Then we will try to activate the first policy which will allow the execution of binaries from a specific DRM variety, which is specified by the DRM variety root hash. Then we first see the content inside. You can see we have the new rules and the new appraised types. And then we try to activate this policy and try to use GCC failed because it is not from a DRM variety volume. Then use password and succeed. Then we will try to get into the permissive mode such that we can use the cat to see the content of other policies. Here for the second one, that will allow the use of a DRM variety volume that is signed by a trusted certificate. Now we try to activate this policy. Now the policy is activated. And we also need to set the enforcement mode. Then GCC failed because it is not inside the DRM variety volume. Then password succeed. So then the final case is the revocation case. In some cases we want to revoke the use of a specific DRM variety volume. And here the policy will deny the use of files from a specific DRM variety volume specified by the root hash. And we can see the content of this policy. Then we try to activate this policy. Also we need to turn on the enforcement mode. Then GCC succeed because it is not in the DRM variety volume. And password denied because it is inside the DRM variety. From here we are going to talk about the IMA extending difficulties and its fundamental limitations. The first problem is IMA measure strongly coupled with a praise. Because IMA has multiple actions, every policy evaluation needs to iterate the whole policy to cover all possible actions. This can be inefficient if the policy only contains one action like a praise. While for IPE, it focuses only on coding integrity. It will make the decision once it finds the first applicable rules inside the policy, which means IPE is more efficient for policy evaluation. The above coupling also causes the IMA policy mechanism or evaluation result to be a bitmap, which contains IMA actions with their parameters. Currently the bitmap has 32 bits. And while with our extension to IMA, 30 bits are using, if only two bits available for the future features. This is not really scalable and can be problematic for new upcoming features. While IPE doesn't have such an issue because the evaluation of IPE policy is just allow or deny the file. All IMA actions happen inside one single function that is process measurement. Extending a praise will make this function more complex and may cause regression to other actions. The second problem is IMA's coding integrity deployment process is complicated. Not only in policy need to be deployed, but the broad-list extended attribute and keyrings are also need to be configured. While for IPE, all you need to do is just to deploy the policy then all set. The final problem is IMA policy heavily coupled with its mechanism. IMA praise decision cannot solely be determined by the policy. It will be affected by the other factors as we just showed. And because the policy cannot fully control the system behavior, this will be headache for the administrators to travel through the machine when failures happen. And more importantly, as we mentioned previously, IMA existing integrity mechanism can be treated by malicious block device. This makes us less likely to use the existing integrity mechanism of IMA. Finally, from our experience of extending IMA, we found it is very hard to extend it for new integrity mechanism. We need to add multiple new IMA flags at different parts of IMA, which is very hard to figure out and hard to maintain the code. Meanwhile, IPE has a modular design. If we want to add a new support for a new mechanism, we just need to add a new single file. And other parts, we don't need to touch the other parts. Then we start the discussions. Here are some facts. As far as we are aware, IMA doesn't have a comprehensive test for appraise. Continue to extend appraise may break the existing features. And because we don't have the test, we don't know what kind of change will break the features. This makes us afraid of continuing to extend it. Microsoft is still using IPE in our internal production system on a daily basis. We're using IPE and IMA simultaneously, but IPE only for code integrity and IMA only for measurement. As we discussed before, the security system level is not ideal for integrity mechanism as it can be easily detected. DM variety, which is in the block device level and FS variety, which is in the file system level, are two good examples of good code integrity mechanisms. The original design of IMA is on top of the action measure, which calculates the file hash before the praise. This essentially means IMA has to do the measurement before the praise every time. However, the measurement is no longer prerequisite for coding integrity. This can be simply proved by the implementation of IPE. We did nothing related to measurement, but still guarantee the system with code integrity. Moreover, if the IPE and IMA are both enabled due to the LSM stacking, if the IPE denies a file, then the IMA's measurement hook won't be triggered. This can let us avoid some useless measurements actions. IPE is perfectly adhering Linux keys principle, which only do one thing, that is code integrity, and do it well. As measurement and code integrity can be totally separate kernel module, we think it should be better to let them separately operating. The prototype the feature to IMA are only a small subset of IPEs. We also support FS variety. We support trust files in Ethereum FS. We support anonymous memory verification. We also have a comprehensive test suite that covers various attack scenarios. The most excited part is the namespace support that will be present by my co-worker Devon this afternoon. This essentially means we can have multiple containers that has different policy deployed and operates cooperatively. Thank you for listening. I'm ready for take any question. Okay, so basically the problem is what kind of the actual mechanism of the coding integrity provided by IMA, right? They will save the pre-computed hash inside the extended attribute of the file system and may sign the hash. And it will configure a key ring of what kind of the certificate to be trust that sign the hash. And also they will have a block test that will just block the file based on the hash. These are the features as far as I know. I think I repeat the question. So the question is the existing coding integrity features of IMA already inside the system. Any else? Okay, I think we are done here. Thank you for listening.