On 06/22/2017 08:26 AM, Stephen Smalley wrote:
On Thu, 2017-06-22 at 08:17 -0700, Bill D wrote:
> On 06/22/2017 07:56 AM, Stephen Smalley wrote:
>
>> On Wed, 2017-06-21 at 14:19 -0700, Bill D wrote:
>>> On 06/21/2017 11:26 AM, Stephen Smalley wrote:
>>>
>>>> On Wed, 2017-06-21 at 10:12 -0700, Bill D wrote:
>>>>> On 06/21/2017 09:23 AM, Stephen Smalley wrote:
>>>>>
>>>>>> On Wed, 2017-06-21 at 08:58 -0700, Bill D wrote:
>>>>>>> Hello,
>>>>>>>
>>>>>>> Is it possible to enforce directory read/write/execute
>>>>>>> control
>>>>>>> using
>>>>>>> categories?
>>>>>>>
>>>>>>> For example, using a category, I would like Linux users
>>>>>>> assigned
>>>>>>> to
>>>>>>> that
>>>>>>> category to have read/write/execute rights to directory
>>>>>>> /opt/foo.
>>>>>>>
>>>>>>> Other Linux users that do not have that category assigned
>>>>>>> should
>>>>>>> not
>>>>>>> have read/write/execute access to /opt/foo
>>>>>>>
>>>>>>> I know this can be done with normal DAC procedures using
>>>>>>> groups
>>>>>>> and/or
>>>>>>> file permission tools such as chmod and chown.
>>>>>>>
>>>>>>> And I also know that it can done with SELinux TE (i.e
>>>>>>> create
>>>>>>> an
>>>>>>> SELinux
>>>>>>> security policy)
>>>>>>>
>>>>>>> But can it be done by using just categories?
>>>>>> Yes, that is how sandbox, libvirt, docker, and other tools
>>>>>> isolate
>>>>>> sandboxes, VMs, containers, etc. And Android uses it for
>>>>>> user
>>>>>> isolation and potentially app isolation in the
>>>>>> future. Categories
>>>>>> are
>>>>>> suitable when your primary goal is isolation.
>>>>>>
>>>>>> In Fedora, you would need to mark the user domains as MCS
>>>>>> constrained
>>>>>> since that is no longer the default. Depending on your
>>>>>> particular
>>>>>> goals, you might need to revise the MCS constraints, but
>>>>>> they
>>>>>> may
>>>>>> be
>>>>>> sufficient as is.
>>>>> Thank you for the information. I am using RHEL 6.9 and
>>>>> CentOS
>>>>> 6.9.
>>>>>
>>>>> Any pointers on how to mark the user domains as MCS
>>>>> constrained
>>>>> and
>>>>> how
>>>>> to view the existing MCS constraints for verification?
>>>> Didn't Philip Seeley provide instructions for using categories
>>>> in
>>>> the
>>>> earlier discussion of controlling execution of Java JAR files?
>>> Yes, I got that.
>>>
>>>
>>>> Looks like RHEL6 defined mcs_untrusted_proc(), while modern
>>>> Fedora
>>>> defines mcs_constrained() (in
>>>> /usr/share/selinux/devel/include/kernel/mcs.if). So, if you
>>>> wanted
>>>> to
>>>> just use user_t for the users, you would do something like:
>>>>
>>>> # Make user_t MCS constrained.
>>>> $ cat mcsconstrained.te
>>>> require {
>>>> type user_t;
>>>> }
>>>> # NB: use mcs_constrained() if on Fedora or RHEL 7.
>>>> mcs_untrusted_proc(user_t)
>>>>
>>>> # Build and install the above policy module.
>>>> $ make -f /usr/share/selinux/devel/Makefile mcsconstrained.pp
>>>> $ semodule -i mcsconstrained.pp
>>>>
>>>> # Define a SELinux user that is authorized only for category 0.
>>>> $ semanage user -a -R user_r -rs0:c0 c0user_u
>>>>
>>>> # Define a SELinux user that is authorized only for category 1.
>>>> $ semanage user -a -R user_r -rs0:c1 c1user_u
>>>>
>>>> # Add a user with category 0 access.
>>>> $ useradd -Z c0user_u jack
>>>>
>>>> # Add a user with category 1 access.
>>>> $ useradd -Z c1user_u mary
>>>>
>>>> # Restrict /opt/foo to category 1 users.
>>>> $ semanage fcontext -a -t usr_t -r s0:c1 "/opt/foo(/.*)?"
>>>> $ restorecon -RF /opt/foo
>>>>
>>>> Then login as jack and see if you can access /opt/foo, and
>>>> ditto
>>>> for
>>>> mary.
>>>>
>>>> I suspect you are better off testing to confirm correct
>>>> operation
>>>> than
>>>> trying to read the constraints, but if you really want them,
>>>> you
>>>> can
>>>> see a version disassembled from binary policy via seinfo --
>>>> constrain,
>>>> or can just download the .src.rpm for selinux-policy and
>>>> extract
>>>> the
>>>> mcs file from it. Looks like RHEL6 did not yet support
>>>> attribute
>>>> preservation in constraints, and still displayed them in
>>>> postfix
>>>> form,
>>>> so the seinfo --constrain output isn't very human-friendly (it
>>>> has
>>>> since improved).
>>> I have tried your steps without success. Here is what I did:
>>>
>>> $ cat /etc/redhat-release
>>> Red Hat Enterprise Linux Server release 6.9 (Santiago)
>>>
>>> # create the folder foo and a bash script
>>> $ mkdir -p /opt/foo
>>> $ echo 'echo hello' > /opt/foo/bar.sh
>>> $ chmod -R 770 /opt/foo
>>> $ chown -R admin:admin /opt/foo
>>> $ chcon -u system_u /opt/foo
>>> $ chcon -u system_u /opt/foo/bar.sh
>>> $ ls -aldtZ /opt/foo/ /opt/foo/bar.sh
>>> drwxrwx---. admin admin system_u:object_r:usr_t:SystemLow
>>> /opt/foo/
>>> -rwxrwx---. admin admin system_u:object_r:usr_t:SystemLow
>>> /opt/foo/bar.sh
>>>
>>> $ getenforce
>>> Enforcing
>>>
>>> $ setenforce 0
>>>
>>> $ getenforce
>>> Permissive
>>>
>>> $ vi /etc/selinux/targeted/setrans.conf
>>>
>>> $ cat /etc/selinux/targeted/setrans.conf
>>> #
>>> # Multi-Category Security translation table for SELinux
>>> #
>>> # Uncomment the following to disable translation libary
>>> # disable=1
>>> #
>>> # Objects can be categorized with 0-1023 categories defined by
>>> the
>>> admin.
>>> # Objects can be in more than one category at a time.
>>> # Categories are stored in the system as c0-c1023. Users can use
>>> this
>>> # table to translate the categories into a more meaningful
>>> output.
>>> # Examples:
>>> # s0:c0=CompanyConfidential
>>> # s0:c1=PatientRecord
>>> # s0:c2=Unclassified
>>> # s0:c3=TopSecret
>>> # s0:c1,c3=CompanyConfidentialRedHat
>>> s0:c0=CompanyConfidential
>>> s0:c1=PatientRecord
>>> s0=SystemLow
>>> s0-s0:c0.c1023=SystemLow-SystemHigh
>>> s0:c0.c1023=SystemHigh
>>>
>>> $ service mcstrans restart
>>> Stopping
>>> mcstransd: [ OK ]
>>> Starting
>>> mcstransd: [ OK ]
>>>
>>> $ chcat -L
>>> s0:c0 CompanyConfidential
>>> s0:c1 PatientRecord
>>> s0 SystemLow
>>> s0-s0:c0.c1023 SystemLow-SystemHigh
>>> s0:c0.c1023 SystemHigh
>>>
>>> $ cat mcsconstrained.te
>>> module mymcsmodule 1.0;
>>>
>>> require {
>>> type user_t;
>>> }
>>> # NB: use mcs_constrained() if on Fedora or RHEL 7.
>>> mcs_untrusted_proc(user_t)
>>>
>>> # Build and install the above policy module.
>>> $ make -f /usr/share/selinux/devel/Makefile mcsconstrained.pp
>>> Compiling targeted mcsconstrained module
>>> /usr/bin/checkmodule: loading policy configuration from
>>> tmp/mcsconstrained.tmp
>>> /usr/bin/checkmodule: policy configuration loaded
>>> /usr/bin/checkmodule: writing binary representation (version 10)
>>> to
>>> tmp/mcsconstrained.mod
>>> Creating targeted mcsconstrained.pp policy package
>>> rm tmp/mcsconstrained.mod tmp/mcsconstrained.mod.fc
>>>
>>> $ semodule -i mcsconstrained.pp
>>>
>>> # Define a SELinux user that is authorized only for category 0.
>>> $ semanage user -a -R user_r -rs0:c0 c0user_u
>>>
>>> # Define a SELinux user that is authorized only for category 1.
>>> $ semanage user -a -R user_r -rs0:c1 c1user_u
>>>
>>> # Add a user with category 0 access.
>>> $ useradd -Z c0user_u jack
>>>
>>> # add jack to the admin group
>>> $ usermod -G admin jack
>>>
>>> # Add a user with category 1 access.
>>> $ useradd -Z c1user_u mary
>>>
>>> # add mary to the admin group
>>> $ usermod -G admin mary
>>>
>>> # Restrict /opt/foo to category 1 users.
>>> $ semanage fcontext -a -t usr_t -r s0:c1 "/opt/foo(/.*)?"
>>> $ restorecon -RF /opt/foo
>>>
>>> $ ls -aldtZ /opt/foo /opt/foo/bar.sh
>>> drwxrwx---. admin admin system_u:object_r:usr_t:PatientRecord
>>> /opt/foo
>>> -rwxrwx---. admin admin system_u:object_r:usr_t:PatientRecord
>>> /opt/foo/bar.sh
>>>
>>> $ setenforce 1
>>>
>>> Now logon as Linux user jack and notice that it is *not* able to
>>> write
>>> to /opt/foo and can't run /opt/foo/bar.sh which is expected
>>>
>>> $ id
>>> uid=502(jack) gid=502(jack) groups=502(jack),501(admin)
>>> context=c0user_u:user_r:user_t:CompanyConfidential
>>>
>>> $ id -Z
>>> c0user_u:user_r:user_t:CompanyConfidential
>>>
>>> $ ls -aldtZ /opt/foo/ /opt/foo/bar.sh
>>> drwxrwx---. admin admin system_u:object_r:usr_t:PatientRecord
>>> /opt/foo/
>>> -rwxrwx---. admin admin system_u:object_r:usr_t:PatientRecord
>>> /opt/foo/bar.sh
>>>
>>> $ touch /opt/foo/bar
>>> touch: cannot touch `/opt/foo/bar': Permission denied
>>>
>>> $ /opt/foo/bar.sh
>>> -bash: /opt/foo/bar.sh: Permission denied
>>>
>>> Now logon as Linux user mary and notice that it is able to run
>>> /opt/foo/bar.sh which is expected.
>>> However, mary is *not* able to write to /opt/foo which is *not*
>>> expected
>>>
>>> $ id
>>> uid=503(mary) gid=503(mary) groups=503(mary),501(admin)
>>> context=c1user_u:user_r:user_t:PatientRecord
>>>
>>> $ id -Z
>>> c1user_u:user_r:user_t:PatientRecord
>>>
>>> $ ls -aldtZ /opt/foo/ /opt/foo/bar.sh
>>> drwxrwx---. admin admin system_u:object_r:usr_t:PatientRecord
>>> /opt/foo/
>>> -rwxrwx---. admin admin system_u:object_r:usr_t:PatientRecord
>>> /opt/foo/bar.sh
>>>
>>> $ /opt/foo/bar.sh
>>> hello
>>>
>>> $ touch /opt/foo/blah
>>> touch: cannot touch `/opt/foo/blah': Permission denied
>>>
>>> Following is the denial details in /var/log/audit/audit.log:
>>>
>>> type=AVC msg=audit(1498079143.988:16822): avc: denied { write }
>>> for
>>> pid=10393 comm="touch" name="foo" dev=dm-5 ino=3801089
>>> scontext=c1user_u:user_r:user_t:s0:c1
>>> tcontext=system_u:object_r:usr_t:s0:c1 tclass=dir
>>> type=SYSCALL msg=audit(1498079143.988:16822): arch=c000003e
>>> syscall=2
>>> success=no exit=-13 a0=7ffda4cab82d a1=941 a2=1b6 a3=7ffda4ca91d0
>>> items=2 ppid=10292 pid=10393 auid=503 uid=503 gid=503 euid=503
>>> suid=503
>>> fsuid=503 egid=503 sgid=503 fsgid=503 tty=pts2 ses=14
>>> comm="touch"
>>> exe="/bin/touch" subj=c1user_u:user_r:user_t:s0:c1
key="access"
>>> type=CWD msg=audit(1498079143.988:16822): cwd="/home/mary"
>>> type=PATH msg=audit(1498079143.988:16822): item=0
>>> name="/opt/foo/"
>>> inode=3801089 dev=fd:05 mode=040770 ouid=501 ogid=501 rdev=00:00
>>> obj=system_u:object_r:usr_t:s0:c1 nametype=PARENT
>>> type=PATH msg=audit(1498079143.988:16822): item=1
>>> name="/opt/foo/blah"
>>> nametype=CREATE
>>>
>>> Does it mean that we have to loosen up the access control for the
>>> usr_t
>>> type such as allowing it to write to directories?
>>> It seems like if we did that, then we would be opening up a
>>> security
>>> hole i.e. regular users can potentially write to the /usr
>>> directory?
>> Sorry, I should have suggested using another type for /opt/foo.
>>
>> semanage fcontext -d "/opt/foo(/.*)?"
>> semanage fcontext -a -t user_home_dir_t -r s0:c1 "/opt/foo(/.*)?"
>> restorecon -RF /opt/foo
> Thanks. That resolves the issue of not being able to write to
> /opt/foo
> but it now blocks executing /opt/foo/bar.sh as follows:
>
> $ id
> uid=503(mary) gid=503(mary) groups=503(mary),501(admin)
> context=c1user_u:user_r:user_t:PatientRecord
>
> $ /opt/foo/bar.sh
> -bash: /opt/foo/bar.sh: Permission denied
>
> And here are the file permissions for /opt/foo/bar.sh
>
> # id
> uid=0(root) gid=0(root) groups=0(root)
> context=unconfined_u:unconfined_r:unconfined_t:SystemLow-SystemHigh
>
> # ls -aldtZ /opt/foo/bar.sh
> -rwxrwx---. admin admin
> system_u:object_r:user_home_dir_t:PatientRecord
> /opt/foo/bar.sh
>
> And here is the denial:
>
> type=AVC msg=audit(1498144073.846:204627): avc: denied { execute }
> for pid=15033 comm="bash" name="bar.sh" dev=dm-5 ino=3801090
> scontext=c1user_u:user_r:user_t:s0:c1
> tcontext=system_u:object_r:user_home_dir_t:s0:c1 tclass=file
> type=SYSCALL msg=audit(1498144073.846:204627): arch=c000003e
> syscall=59
> success=no exit=-13 a0=21bf870 a1=21b2f50 a2=21be210 a3=10 items=1
> ppid=14879 pid=15033 auid=503 uid=503 gid=503 euid=503 suid=503
> fsuid=503 egid=503 sgid=503 fsgid=503 tty=pts1 ses=155 comm="bash"
> exe="/bin/bash" subj=c1user_u:user_r:user_t:s0:c1 key=(null)
> type=CWD msg=audit(1498144073.846:204627): cwd="/home/mary"
> type=PATH msg=audit(1498144073.846:204627): item=0
> name="/opt/foo/bar.sh" inode=3801090 dev=fd:05 mode=0100770 ouid=501
> ogid=501 rdev=00:00 obj=system_u:object_r:user_home_dir_t:s0:c1
> nametype=NORMAL
Sigh, if at first you don't succeed,
semanage fcontext -m -t user_home_t -r s0:c1 "/opt/foo(/.*)?"
restorecon -RF /opt/foo
That worked! Thanks!
Regards,
Bill