官术网_书友最值得收藏!

Putting it together

SELinux labels are quite flexible and sometimes complex. It's often beneficial to start with a contrived example that focuses on type enforcement. Later, we can add additional fields later as the need for finer granularity becomes more apparent. Conveniently, you can project this model to scenarios in everyday life to provide some sense of tangibility to the material. Dan Walsh, a prominent SELinux figure, posted a blog post using pets as an analogy. Let's continue on with that premise, but we will make some modifications as we go and define our own examples. It's best to start with simple type enforcement as it is the easiest to understand.

Note

You can read Dan Walsh's original blog post introducing the pet analogy at http://opensource.com/business/13/11/selinux-policy-guide.

Suppose we own a cat and a dog. We don't want the cat to eat dog food. We don't want the dog to eat cat food. At this point, we have already identified two subjects, a cat and a dog, and two targets, cat food and dog food. We also have identified an access vector, eating. We can use allow rules to implement our policy. Possible rules could look like this:

allow cat cat_chow:food eat;
allow dog dog_chow:food eat;

Let's use this example to start and define a basic syntax for expressing the access controls we would like to enforce. The first token is allow, stating we wish to allow an interaction between a subject and a target. The dog is assigned the type, dog, and the cat, cat. The cat food is assigned the type cat_chow, and the dog food, dog_chow. The access vector in this case is eat. With this basic syntax, which is also valid SELinux syntax, we restrict the animals to the food they should eat. Notice the :food annotation after the type. This is the class field of the target object. For instance, there might also be dog_chow treat and cat_chow classes that could indicate our desire to allow access to treats in a fashion that is potentially different from the way we allow access to foods that are not treats.

Let's say we get two more dogs, and our scenario has three dogs. The dogs are of different sizes: small, medium, and large. We want to make sure none of these new dogs eat others' food. We could do something like create a new type for each of the dogs and prevent dogs from eating the food of other dogs. It would look something like this:

allow cat cat_chow:food eat;
allow dog_small dog_small_chow:food eat;
allow dog_medium dog_medium_chow:food eat;
allow dog_large dog_large chow:food eat;

This would work; however, the total number of types would be difficult to manage, and that would continue to grow if we allow the large dog to eat the smaller breeds' food. What we could do is use MLS support to assign a sensitivity to each target or dog food bowl. Let's assume the following:

  • The cat's food bowl has sensitivity, tiny
  • The small dog's food bowl has sensitivity, small
  • The medium-sized dog's food bowl has sensitivity, medium
  • The large dog's food bowl has sensitivity, large

We also need to make sure that the subjects are labeled with the proper sensitivity as well:

  • The cat should have sensitivity, tiny
  • The small dog should have sensitivity, small
  • The medium-sized dog should have sensitivity, medium
  • The large dog should have sensitivity, large

At this point, we need to introduce additional syntax to allow the interactions, since by default, MLS allows everything and TE denies everything. We'll use mlsconstrain, to restrict interactions within the system. The rule could look like this:

mlsconstrain food eat (l1 eq l2);

This constraint only allows subjects to eat food with the same sensitivity level. SELinux defines the keywords l1 and l2. The l1 keyword is the level of the target and l2 is the level of the source. Because the rules are part of a whitelist, this also prevents subjects from eating food that does not have the equivalent sensitivity level.

Now, let's say we get yet another large dog. Now we have two large breed dogs. However, they have different diets and need to access different foods. We could add a new type or modify an existing type, but this would have the same limitations that led us to use sensitivities to prevent access. We could add another sensitivity, but it might get confusing that there are large1 and large2 sensitivities. At this point, categories would allow us to get a bit more granular in our controls. Suppose we add a category denoting the breed. Our MLS portion of our label would look something like this:

large:golden_retriever
large:black_lab

These could be used to prevent the black lab from eating the golden retriever's food. Now suppose you're surprised with another dog, a Saint Bernard. Let's say this new Bernard can eat any large dog's food, but the other large dogs can't eat his food. We could label the food bowls and the dogs.

The existing mlsconstraint needs modification. If the Saint Bernard ran out of food and went to the Black Lab's dish, the Saint Bernard would not be able to eat from it since the levels are not equal (Dog:large:saint_bernard, black_lab, golden_retriever is not the same as dog_chow:large:black_lab). Remember, the levels are sets, so we need to introduce some notion that if the subjects set dominates the target set, that interaction should be allowed.

This could be accomplished with the dom keyword:

mlsconstrain food eat (l1 dom l2);

The dominate keyword, dom, differs from equality, indicating l1 is a superset of l2 In other words, the levels associated with the target, l2, are among the potentially larger set of levels associated with the subject, l1. At this point, we are able to keep all the food separated and used however we see fit.

After getting all these dogs, you realize it's time to feed them, so you get a bag of dog food and put some in each bowl. However, before you can add dog food to the bowls, we need some allow rules and labels that will let you. Remember, SELinux is a whitelist-based system, and everything must be explicitly allowed.

We will label the human with the human label and define some rules. Oh yeah... don't forget to feed the cat, as well:

allow human dog_chow:food put;
allow human cat_chow:food put;

We will also need to label human with all the sensitivities and categories, but this would become cumbersome when we need to add additional dogs, breeds, and breed sizes to our system. We could just bypass the constraint if the type is human. With this approach, we always trust human to put the correct food in the appropriate bowl:

mlsconstrain food eat (l1 dom l2);
mlsconstrain food put (t1 == human);

Note the addition of put in the access vectors of the MLS constraint. Viola! The human can now feed his ever-growing pack of animals.

So your birthday rolls around, and you receive an automatic dog feeder as a present. You label the food dispenser, dispenser and modify the MLS constraints:

mlsconstrain food eat (l1 dom l2);
mlsconstrain food put (t1 == human or t1 == dispenser);

Again, we see a need to condense the number of types and get organized to prevent having to duplicate lines. This is where attributes are quite handy. We can assign an attribute to our human and dispenser types by first defining the attribute:

attribute feeder;

Then we can add it to the type:

typeattribute human, feeder;
typeattribute dispenser, feeder;

This could also be done at type declaration:

type human, feeder;
type dispenser, feeder;

At this point, we could modify the MLS statements to look like this:

mlsconstrain food eat (l1 dom l2);
mlsconstrain food put (t1 == feeder);

Now let's suppose you hire a maid service. You want to ensure anyone sent by the maid service is able to feed your pets. For that matter, let's let your family members feed them, as well. This would be a good use case for the user capabilities. We will define the following users: adults_u, kids_u, and maid_u. Then we'll need to add a constraint statement to allow interactions by these users:

mlsconstrain food put (u1 == adults_u or u1 == maid_u);

This would prevent the kids from feeding the dogs, but let the maids and adults feed them. Now suppose you hire a gardener. You could create yet another user, gardener_u, or you could collapse the users into a few classes and use roles. Let's suppose we collapse gardener_u and maid_u into staff_u. There is no reason the gardener should be feeding the dog, so we could use role-based transitions to move the staff between their duties. For instance, suppose staff can perform more than one service, that is, the same person might garden and clean. In this case, they might take on the role of gardener_r or maid_r. We could use the role capability of SELinux to meet this need:

mlsconstrain food put (u1 == adults_u or (u1 == staff_u and r1 == animal_care_r);

Staff may only feed the dogs when they're in the animal_care_r role. How to get into and back out of that role is really the only component missing. You need to have a well-defined system for how the staff can move into the animal care role and transition back out. These transitions in SELinux occur either automatically via dynamic role transitions or via source code modifications. We'll assume that any human entity (gardener, adults, kids) all start in the human_r role.

Dynamic role transitions work with a two-part rule, the first part allows the transition to occur via an allow rule:

allow human_r animal_care_r;

The role transition statements are as follows:

role_transition human_r dog_chow animal_care_r;
role_transition human_r cat_chow animal_care_r;

This would be a good case to attribute the dog_chow and cat_chow types to a new attribute, animal_chow, and rewrite the preceding role transitions to:

typeattribute dog_chow, animal_chow;
typeattribute cat_chow, animal_chow;
role_transition human_r animal_chow animal_care_r;

With these role transitions, you can only go from the human_r role to animal_care_r. You would need to define transitions to get back as well. It's also important to note that you might define other roles. Suppose you define the role gardener_r, and when someone is in that role, they cannot transition to animal_care_r. Suppose your justification for this policy is that gardeners might work with chemicals unsafe for pets, so they would need to wash their hands before feeding pets. In such a situation, they should only be able to transition to animal_care_r from the hand_wash_r role.

主站蜘蛛池模板: 青州市| 张掖市| 和平县| 洪泽县| 马鞍山市| 玉龙| 蒙阴县| 榕江县| 灵川县| 雷山县| 饶平县| 遂宁市| 阳山县| 庆云县| 招远市| 宿迁市| 丰宁| 昌图县| 晋州市| 合作市| 息烽县| 桂东县| 龙门县| 日照市| 洪洞县| 黑水县| 本溪市| 雅江县| 多伦县| 宜兴市| 昭觉县| 杨浦区| 江孜县| 交口县| 白玉县| 佛教| 海宁市| 察雅县| 油尖旺区| 化德县| 高雄县|