lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <10247DAA-D04B-42D5-B67B-C2D3BD42A94F@mac.com>
Date:	Sun, 12 Aug 2007 21:38:39 -0400
From:	Kyle Moffett <mrmacman_g4@....com>
To:	casey@...aufler-ca.com
Cc:	linux-security-module@...r.kernel.org,
	LKML Kernel <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH] Smack: Simplified Mandatory Access Control Kernel

On Aug 12, 2007, at 15:41:46, Casey Schaufler wrote:
> --- Kyle Moffett <mrmacman_g4@....com> wrote:
>> On Aug 11, 2007, at 21:21:55, Casey Schaufler wrote:
>>> --- Kyle Moffett <mrmacman_g4@....com> wrote:
>>>> I was considering compiling the complete list, but such an  
>>>> exercise would take me at least an hour to do properly and which  
>>>> categories individual permissions should be placed in could be  
>>>> argued for weeks.
>>>
>>> I will be happy to consider your arguement when you are willing  
>>> to present the complete argument.
>>
>> Here's my complete argument:
>>
>> Regardless of how you categorize "read", "write", "execute", and  
>> "doesnt-need-protection" in your policy language, I can write an  
>> SELinux policy and a list of labels which expresses that policy.    
>> Moreover, without too much work I can probably write a Perl script  
>> to do it for you.  On the other hand I can only do that if you  
>> tell me exactly how you want to categorize those things, though.   
>> In my personal opinion they cannot be reasonably categorized  
>> without breaking all sorts of tools or leaving gaping holes;  
>> precisely the reason that SELinux uses such a fine-grained list.
>
> This identifies an important design philosophy issue, that being  
> what granularity is appropriate. I have no interest in composing a  
> description of Smack at the granularity that SELinux uses.

If you have no interest in categorizing the SELinux access vectors,  
then how do you expect to categorize the LSM hooks, which are almost  
1-to-1 mapped with the SELinux access vectors?


> The point you make, that you need to have that in order to create a  
> policy description, is one of the reasons for Smack. Simplified.

Well yes, but a simplified policy is useless if it uses no LSM  
hooks.  I will write you a Perl script which will generate a complete  
and functionally equivalent SELinux policy (assuming I have enough  
free time) given a file with your policy language.  But I can do this  
if and only if you tell me which of the SELinux access vectors you  
care about (In other words, which of the LSM hooks you want to  
require "read", "write", or "execute" privileges for).  With such a  
little script you could write all the "simplified" policy you want,  
without having to change the kernel code at all.


>> Ok, you want sample policy to match your "MLS" sample?  For  
>> convenience here's one more macro:
>> define(`rx',`r(`$1',`$2') x(`$1',`$2')')
>>
>> type unclass;
>> type c;
>> type s;
>> type ts;
>> rx(c, unclass)
>> rx(s, c)
>> rx(s, unclass)
>> rx(ts, s)
>> rx(ts, c)
>> rx(ts, unclass)
>>
>> In case you don't have the policy you typed into your email, it  
>> looks almost identical with a few exceptions for slightly modified  
>> syntax:
>>> C        Unclass rx
>>> S        C       rx
>>> S        Unclass rx
>>> TS       S       rx
>>> TS       C       rx
>>> TS       Unclass rx
>
> Yup. Your macro invocations look very much like the Smack  
> specification.  Your macro definitions are of course unnecessary in  
> Smack, and you really ought to be using the MLS labels SELinux  
> supports, and you need a base policy underneath this.

My point is your policy format is SO simple it doesn't even need the  
SELinux MLS code to handle it.  From the way you've described it the  
base policy (~200 lines) would be *identical* regardless of the  
entries in your policy language, and the rest could be generated by a  
script directly from the "C Unclass rx"-type stuff.

>> Whoops, I think I must have smashed the delete key or something  
>> while sending.  Here's the paragraphs which got elided:
>>
>> Well, yes, but a policy which completely ignores future  
>> expandability can't be expanded upon regardless. It would also be  
>> very hard to add new policy without a lot of duplication under  
>> your system. On the other hand, with SELinux you can very easily  
>> add attribute-based policy so adding new capabilities is as simple  
>> as sticking existing attributes on newly defined types.  For example:
>>
>> type my_log_t, file_type, log_file;
>> type my_log_daemon, daemon;
>>
>> Right there I just gave permission for the logrotate to recycle  
>> files labelled my_log_t, which the sysadmin and audit admin can  
>> also read (and the audit admin can delete).  I also gave  
>> permission for my daemon to send SIGCHLD to init, and for init/ 
>> initscripts to send it a SIGTERM/SIGQUIT.  All without writing a  
>> SINGLE policy rule.  Basically all of those existing behaviors are  
>> found in allow rules built on the "file_type", "log_file", and  
>> "daemon" attributes.
>
> Ah, now you're refering to the reference policy, right?

Yes, precisely.  For most of that functionality there are existing  
attributes and types defined in the reference policy to make custom  
policy much easier.  Furthermore, there are interface files which  
allow me to say something like "Let this program spawn an Apache  
daemon in the right domain" with a single line.  If I only want to do  
that when the "httpd" module is loaded I can put the line in an  
"optional" block.  A policy for a basic network daemon with a couple  
log files, a config file, and a little database is all of 30 lines,  
maybe 50 if you throw in comments.


>>> They can be added or changed one by one as required while the  
>>> system is running, and there are uses that exploit that. One  
>>> example is to put the label "Game" on certain programs and:
>>>
>>>    at 8:00am "Worker Game no"
>>>    at 5:00pm "Worker Game x"
>>>
>>> Thus Worker processes can access Game files only during off hours.
>>
>> This is fundamentally broken:
>> [...]
>> Secondly, you can already do the same thing with DAC and a PAM  
>> groups-from-time-of-day module, I don't see why such a thing is  
>> special enough to need MAC.  Thirdly, I could do exactly the same  
>> thing with an SELinux boolean and a cronjob (once we get proper  
>> revoke support):
>
> There is usually a way to address any particular problem using DAC,  
> it's often sufficiently painful that MAC looks like a better approach.

No, generally the only reason to use MAC is when it's security- 
critical (system compromise, classified data, critical  
infrastructure, etc).  Denying users access to games during the  
workday is hardly "security-critical".  If that system's CPU time was  
exclusively needed for a life support machine during the day then  
maybe, but that's what renice or realtime scheduling are for and why  
the hell are you installing games on a heart monitor?


> Your boolean solution requires more forthought than the Smack rule  
> solution, but I'll give it to you once you've fleshed out your "##"  
> lines.

How does it require more forethought?  When I want to turn it on, I  
write and load the 5 line policy then add the cronjobs.  Yours  
involves giving cron unconditional permission to write to your  
security database (always a bad idea) and then adding similar cronjobs.


>> ## Rule to allow cron to tweak the "can_play_games" boolean value

Hmm, looking at this again the current policy language doesn't have a  
way of delegating access to boolean values, so there's no way to let  
cron directly poke at booleans right now.  You could do it with this  
shell script:

#! /bin/sh
now=$(date +'%H%M')
if [ 800 -le "$now" -a 1700 -ge "$now" ]; then
	setsebool can_play_games false
else
	setsebool can_play_games true
fi


Label that script as games_changer_exec_t then use this bit of policy
   type_transition cron_t games_changer_exec_t:process games_changer_t;
   can_setbool(games_changer_t);


>> if (can_play_games) {
>> 	## Insert game-playing allow rules here
>> }

Once you have written a policy specific to the game you want to allow  
or disallow, you would just put that policy inside of the  
conditional.  As a simple policy example for the ping program (from  
an older refpolicy, now a bit out of date, but still useful as an  
example):

## The ping domain
type ping_t, domain, privlog;

## Daemons, sysadmins, and users may assume the ping type if allowed  
below
role system_r types ping_t;
role sysadm_r types ping_t;
in_user_role(ping_t)

## The ping binary
type ping_exec_t, file_type, sysadmfile, exec_type;

## Allow the sysadmin and init scripts to run ping
domain_auto_trans(sysadm_t, ping_exec_t, ping_t)
domain_auto_trans(initrc_t, ping_exec_t, ping_t)

## Boolean controlling user access to ping
bool user_ping false;
if (user_ping) {
	domain_auto_trans(unpriv_userdomain, ping_exec_t, ping_t)
	allow ping_t { ttyfile ptyfile }:chr_file rw_file_perms;
}

## Allow ping to do what it needs to do
uses_shlib(ping_t)
can_network(ping_t)
can_ypbind(ping_t)

## Allow additional permissions that ping needs to operate
allow ping_t etc_t:file { getattr read };
allow ping_t self:unix_stream_socket create_socket_perms;
allow ping_t self:rawip_socket { create ioctl read write bind getopt  
setopt };
allow ping_t netif_type:netif { rawip_send rawip_recv };
allow ping_t node_type:node { rawip_send rawip_recv };
allow ping_t self:capability { net_raw setuid };

## Allow ping to poke at the terminal
allow ping_t admin_tty_type:chr_file rw_file_perms;
allow ping_t { userdomain privfd kernel_t }:fd use;

## Ping wants to get FS attributes and look in /var but doesn't need to
dontaudit ping_t fs_t:filesystem getattr;
dontaudit ping_t var_t:dir search;


It should be pretty clear what every part of the policy is there for;  
basically that's the minimum necessary set of permissions for ping to  
run, with an optional boolean to control user pings.  There's also a  
macro to give your arbitrary process the ability to run ping, such as  
for the "heartbeat" daemon for example.


>>> As far as relabeling the file system goes, the rules apply to  
>>> processes and objects, not to programs. The label on a program  
>>> describes who can access it, it will run with the label of the  
>>> process that exec's it. A change in the rules does not require a  
>>> change to the labels on the file system for things to work  
>>> according to the rules of engagement.
>>
>> By this logic, every program will always have the same label,  
>> unless you recode every program to explicitly change it when it  
>> starts; precisely the thing that the SELinux type transitions were  
>> designed to avoid.
>
> Yes. This is the way it should be. A small set of very carefully  
> analysed programs that change labels under carefully controlled  
> circumstances is what I want. login, sshd, cron, special purpose  
> launchers. Written with the assumption that they will be attacked.

Well, under SELinux, all 3 of those processes go through the special  
purpose PAM module to get their labels changed.  Are you planning to  
modify *every* daemon to have special type-changing code?  Hell, most  
don't even have setuid/chroot support and that's all of 15 lines of  
code and is supported in every UNIX/Linux distro released in the last  
10 years (or more).  Besides, why allow the program (say, "ping") to  
change its own label when the policy could forcibly change it for  
you.  The label change is NOT just to *give* permissions, it's also  
to take them away.  For example, when I run "ping", the process gains  
raw network access but loses access to almost every user file and  
disables LD_PRELOAD, etc, making it a thousand times harder to  
compromise it from the inside too.

>>>> When you change the meaning of new types, you clearly would need  
>>>> to first reload the policy then relaunch programs or relabel  
>>>> files to take advantage of the new types, otherwise they would  
>>>> be categorically ignored by the system.
>>>
>>> I'm sorry, but again, I don't know what you mean by "changing the  
>>> meaning of new types".
>>
>> Oh, say something like "Oh, drat, I wanted this daemon to run as  
>> some other type".
>
> Sorry, "type" is a meaningless attribute in Smack.

Sorry for being unclear.  Assume s/type/label/g; the question still  
stands.


>> Unless you relabel the files and relaunch the daemon the system  
>> will have no idea how the system will change.  And if you let  
>> arbitrary root processes relabel things on the fly then you've  
>> lost all the security advantages to a MAC system.
>
> MAC systems have been behaving this way for decades. SELinux is the  
> exception, not the rule on this.

"People have been burning witches for decades, that must be the right  
thing to do"

The fact that something is commonly done does not make it right,  
especially when there is a significantly more secure alternative  
available.


>> I think you may be making assumptions about the behaviour of  
>> SELinux based on what other OSes do which don't hold:
>>
>> (a)  SELinux does not care about user id, current directory, time  
>> of day, etc.  It cares solely about 3 things:  the Subject, the  
>> Object, and the Action.  For example, if an init script attempts  
>> to execute the apache binary then SELinux gets the following data  
>> for parameters: subject="system_u:system_r:initrc_t:SystemLow- 
>> SystemHigh" object="system_u:object_r:httpd_exec_t:SystemLow"  
>> action="file->execute".
>
> Yes, and each of the components of the subject and object contexts  
> is dependent on a more circumstances than I'd care to deal with.   
> You've demonstrated that SELinux implements fine granularity.

The beauty of fine granularity is that you can ignore it without  
changing code.  If you don't want to use the "user" and "role"  
portions, then just set them to always be "allusers" and "allroles"  
and be done with it.  If you don't want MLS then just define one  
sensitivity (s0) and no categories.  Likewise if want your system to  
use only 8 types then only define 8 types.  It's just that easy!   
Admittedly your policy can't then deal with most of the real-world  
situations (like logging in or running the "passwd" command), but  
that's your choice.


>> (b)  SELinux does NOT have a capability which overrides it.  If  
>> you want to do something that the policy categorically does not  
>> allow, you have 2 choices:  change the policy or disable SELinux.   
>> You can also use a policy which disables both of those options
>
> Yup. I think that's bad.

Which part do you think is bad?  The fact that the policy is  
guaranteed to be non-overrideable, or the fact that you can even  
prevent changing the security policy from the policy?  If you really  
want a root-hole in the policy then you can write one, see the  
"unconfined_t" in the "targeted" policy.


> And Bell & LaPadula using a combination of levels and categories is  
> probably the Smack worst case. But guess what?  The dig against  
> that policy has always been that no one wanted to combine levels  
> and categories.

So how would you secure a system moving data between 3 TS/SCI  
compartments and a Secret network?   You can say "no one wanted  
to...", but we have a couple million dollars worth of business that  
says they do.


>> Ok, fine, how does "moving data around a system" require anything  
>> more than bog-standard user-level privileges?  Normal users under  
>> Linux are not permitted to change "security.*" attributes at all,  
>> but they may bind to sockets, etc.  You can define a "capability"  
>> which lets you do all that, but then you're just blindly giving  
>> processes more privileges than they need to complete an  
>> operation.  Why should you get the "rename all files" priv when  
>> all you need is "Make my log files get $LABEL when I put them in / 
>> var/log/mydaemon/"?
>
> Privilege granularity is a seperate issue. Smack uses Linux  
> privilege machanisms and is happy to do so.

"Linux privilege mechanisms" covers no less than 20,000 lines of  
code, including DAC, capabilities, LSM, namespaces, keyrings, and  
more.  Please be more specific here.

>>>> Why should it?  Admittedly, moving data from "TopSecret" to   
>>>> "Secret" requires a process labeled with a range including at  
>>>> least "S-TS"  *and* with the MLS "read-to-clearance" attribute,  
>>>> but you can be as stingy with that attribute as you like.
>>>
>>> Yup. And plenty of people like you think that is really spiffy.
>>
>> Please explain why you think it isn't?
>
> I grew up believing that downgrading classified information should  
> always be an explicit, concious act.

It still is in SELinux too.  The only difference is that in SELinux  
*all* of the possible ways to downgrade classified information are  
listed for you in the policy file for easy analysis; one of the most  
common complaints about SUID binaries in UNIX is that they aren't all  
listed in one place for easy auditing.  Moreover, you can see exactly  
how the information may be downgraded.  For example, in one policy I  
use, I can prove that specific components of our guard software have  
permission to move data from a category such as "Secret:NukeTesting"  
to just "Secret", but cannot access "TopSecret".  I can also verify  
that the program itself cannot modify the levels it has access to,  
even though it does have permissions to move data between them.  It  
doesn't make you immune to flaws, but it lets you vastly limit the  
damage any given flaw can accomplish.


>> You can call them "process capabilities" or "magic attributes",  
>> they're the same thing, just more fine-grained.  Instead of (Note:  
>> r1 == subject role, r2 == target role, t2 == target type):
>>    mlsconstrain process transition ( (r1 == r2) || (t1 ==   
>> i_am_a_role_changing_capability) )
>>
>> you have (Note: t1 == subject type):
>>    mlsconstrain process transition ( (r1 == r2) || (r1 == system_r  
>> && t1 == i_am_a_login_process && t2 == i_am_a_user_entrypoint) )
>>
>> The latter is like the former, except instead of one single  
>> ultimate "change-any-role" capability, you have a capability which  
>> allows a system login process to change roles *ONLY* if it's also  
>> changing to a user entrypoint.  Please tell me which you think is  
>> more secure.
>
> Don't look at me. A well written program could do fine with either.

The WHOLE POINT of a mandatory access control system is to protect  
against *poorly* written programs.  If we can verify the kernel (~8  
million lines), and the policy (~8,000 lines), then we've saved  
ourselves from having to audit all of userspace (~80+ million  
lines).  Seems a worthy goal to me.


>>>> So the implicit labeling of files actually restricts every  
>>>> process *FURTHER*.  They no longer have even an inkling of a  
>>>> choice about file labeling, and that's a GOOD thing.
>>>
>>> That's true about Smack, you know. The process has no choice  
>>> about the label that the files get.
>>
>> So how do you selectively label files based on criteria such as  
>> "where did I get put"?  How do you distinguish between a "log  
>> file" which is create-and-append-only, a "database file" which I  
>> can modify however I want to, and a "unix socket" which I can bind  
>> in /var/run and get connections from user processes?
>
> I don't. They're all objects.

And by extension you have no way of saying "The apache log files  
can't be modified after they are written."  That feature is part of  
virtually every MAC system anybody's ever made, precisely because you  
can't really trust audit logs without it.

>>> Thank you for your comments.    I hope that I have made the  
>>> behavior and value of Smack clearer in responding to them.
>>
>> You're welcome.  I endeavor to poke my nose into every little LSM- 
>> related corner in the kernel, this one included.
>
> Why?

Firstly because it's interesting, and secondly because it's related  
to my work (which of course comes back to point 1) :-D.

Cheers,
Kyle Moffett
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ