[apparmor] Apparmor: Query

John Johansen john.johansen at canonical.com
Tue Aug 11 07:26:33 UTC 2020


On 8/9/20 4:20 PM, Murali Selvaraj wrote:
> Hi John, Seth, 
> 
> Thanks again for the details. I would like to get your inputs and clarify my understanding.
> Please go through the trailing email and correct me if I am wrong.
> 
> *Goal:* Reducing root permission of the process and enabling required capabilities for the process.
> 
> *Design and approach:*
> 
> - To identify the required CAPs for the process, we are planning to enable all CAPs while running in "non-root"
>   mode and from apparmor logs, hopefully we would be able to find the required capability list for the process
>   specific.
> 

okay

> - Please note that our user "non-root" (UID) is fixed. we won't change the user UID and GID for non-root.
> 

okay

> *Implementation:*
> 
> - Process would be starting as "root" and dropping to non-root then applying required CAPs based on above apparmor logs
>   using libcap APIs.
> 

Is this for discovering the CAPs or deployment.

This will not work for discovering, but will work for deployment.

The CAPs set and apparmor capability rules are independent. The CAPs set will generally be checked first and then the
AppArmor profile. To learn CAPs from AppArmor logging the CAPs set must allow the CAP and then AppArmor will get
a chance to mediate it, and that is when AppArmor will generate the log.


> - Most of the process needs CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH to read/write root privilege files/directories.
> 

Err, I assume for your application

> *Query specific to above non-root approach: *
> 
> - We are planning to enable CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH CAPs when the process switches to non-root.
> - Then based on a process for example network specific process, we will enable CAP_NET_ADMIN.
> - In case of system specific processes to access hardware details, we will enable CAP_SYS_ADMIN.
> - Please note, we will require CAPs based on apparmor logs as indicated above.
> 
right

> Here, the doubt is that if we enable CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_NET_ADMIN, CAP_SYS_ADMIN to run
> the process in non-root to ensure it works in the same way when it was running in "root".
> 
> Do you think enabling CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_NET_ADMIN, CAP_SYS_ADMIN in the process
> are we missing any security or this is expected while using Linux capabilities for non-root (dropping root privilege).
> 
> Please share your valuable suggestions on security specific views.
> 

That depends on how you look at it, but generally I would say its a win

if you applications needs those caps then traditionally it has to be root and it will have a larger cap set than that. It is also hard to distinguish different root processes from each other. So moving the application into a non-root process with limited caps is a security win. The process isn't going to have any more privs than root would and it likely has less and will be logged as a different user as well which is nice for analysis if it is ever needed.

Now if you are worried about giving CAPs and running AppArmor in complain mode, that is indeed a concern. The application will have caps and AppArmor will allow and log accesses. This is fine in a safe environment but not in production. In that case you want to do you might want to develop a base profile with CAPs and deploy that in enforce mode to catch any additional CAPs needed. Each CAP would be denied and logged, and you could then decide whether it is a CAP you want to add.


> *General query:*
> 
> - Is Linux capabilities belong to DAC or LSM/MAC?
> As per my understanding, Linux capabilities are part of LSM. But I still think that few CAPs are used in DAC.
> Please share the details with example.
> 

It is both. The Linux kernel always applies DAC and capability checks, and then it gives the LSM a chance to mediate on operations as well. So CAP checks go through the regular CAPs unix cap checks and then go through the LSM.

This is why you need to set caps on a task in both the capability set and the apparmor profile.


> - Is LSM mandatory to enable in Linux Kernel?
> 
no. If the LSM is not enabled you get DAC and capability checks. Even when the LSM is enabled you still get DAC and capability checks, the LSM can NOT override them, it can only provide further restrictions.

> - Which LSM is enabled in linux by default?
> 
that is a distro decision. Some distros don't enable the LSM by default, some enable apparmor (ubuntu, suse, debian, ...), some enable selinux (fedora, RHEL, android, ...), some enable smack (tizen, automotive grade linux, ...). I should not that modern LSM allows some stacking as well so a distro may have multiple LSM modules enabled.

Eg. Ubuntu has lockdown,yama,apparmor LSMs enabled

 
> - Why do we need MAC as we have a security check by discretionary access controls (DAC) ?

MAC is a different style of security than DAC. MAC provides finer grained mediation/security, it can enforce security models like Multi-layer security with constraints on who can read down/read up and most importantly it doesn't allow the user to change or by-pass the rules enforced by the system.

Do we need MAC? That depends on your security requirements. Governments require MAC on their secure systems. Android uses MAC to enforce better isolation between apps and the system, IOS uses a MAC, even MacOS X Gatekeeper sandbox.

MACs allow can be used to implement sandboxing (isolation) but also controlled sharing.

They certainly aren't the only way to achieve this, you can also do finer grained security with capability systems like capsicum, or pure sandboxing via containers or VMs.

I should note that the LSM is not just for MACs. The LSM is a security framework for the Linux kernel that can provide different types of security. Lockdown, loadpin and yama are all examples of LSMs that are not MACs.


> Is MAC mandatory to enable or optional?
> 
optional

> - Is MAC really mandatory for Linux? AS per my understanding, for embedded linux devices no need to enable MAC on production devices.
>  

It is optional. You can build the kernel without any LSM support by disabling its config. You can also build the kernel with LSMs and disable them via the kernel commnand line options.

  security=
  lsm=

I should note that if you are using secure boot changing or disable the LSM via kernel command line options may not be allowed.

So it also depends on what you mean by optional. If you are rolling your own system, its completely optional, but on locked down systems it may be required unless you have the signing keys to.



> Thanks
> Murali.S
> 
> On Wed, Aug 5, 2020 at 3:25 AM John Johansen <john.johansen at canonical.com <mailto:john.johansen at canonical.com>> wrote:
> 
>     On 8/4/20 7:46 PM, Murali Selvaraj wrote:
>     > Thanks for the explanation.
>     >
>     > Goal: Converting root process to non-root process by enabling required capabilities for the process.
>     >
>     > Scope: Am trying to find out required capabilities for the process which is going to run as "non-root"
>     >
>     > How to use Apparmor to find the capabilities specific to process:
>     >
>     > -> As per above discussion, Apparmor does not grant the required capabilities.
>     >
>     > -> We had thought that, from apparmor logs, we would be able to find the required capabilities.
>     >
>     > -> To find this, we would be following the steps to find the capabilities.
>     >
>     > Process (A) will be running in "non-root" but with all enabled capabilities and check the apparmor logs.
>     > Apparmor logs will show the required capabilities.
>     > Capture these CAPS and use this CAPS in the process code to convert that process root to non-root by only enabling this CAPs observed in apparmor logs.
>     >
>     > Is above understanding correct? please confirm the steps if anything is missing.
>     >
> 
>     Yes AppArmor with the caveat that the "non-root" user is the one you plan to use in the future. Any "non-root" user will likely work but I can't guarantee it unless you use the same uid.
> 
> 
> 
> 
> 
>     > *General Query:*
>     >
>     > In any event, AppArmor will usually see capability requests after the usual DAC permissions are handled.
>     >
>     > Can you please explain this above statement with simple example?
>     >
> 
>     The kernel applies multiple checks (eg. input validation) and the kernel bails on the first failed check. A pseudo code of this idea is
> 
>       fn () {
> 
>         if (input bad)
>            return fail;
> 
>         if ( task uid != object uid) {
>            if ( not capable (CAP))
>              return fail;    }
>         if ( not APPARMOR_CAP(CAP))              <---- AppArmor will log if we get here
>            return fail;
>       }
> 
> 
>     The kernel generally does multiple checks like explained in the pseudo code above. The general pattern is the same as in the pseudo code too. That is input validation comes first, then object lookup, then DAC based permission check (regular unix capability and uid checks), and then the LSM (apparmor) based checks.  But code gets grouped into reusable fns and some time fn order can result in a MAC (apparmor) happening before the DAC check.
> 
>     The overlarching pattern is DAC comes first but there are a few cases where AppArmor is checked first, however you can be assured all required checks will happen.
> 
> 
>     > For example, Process (x) tries to open a file (/etc/security) which is root permission but the process (x) runs in "non-root mode.
>     > Pls note, process (x) does not have permission to open this file ((/etc/security) )
>     >
>     > open => sys_open() => kernel further code for handing the code.
>     >
>     > sys_open() => will return permission denied error due to permission issue.
>     >
>     > Here, capable() check won't happen. Does DAC take care of this check without using capability (CAP_DAC_READ_SEARCH)?
>     >
> 
>     yes DAC includes uid and guid checks. The capability call for CAP_DAC_READ_SEARCH only happens if the uid/guid checks fail.
> 
>     > In such a case, trying to understand when Kernel uses capable() to check CAP_DAC_READ_SEARCH/CAP_DAC_OVERRIDE before/after DAC.
> 
>     these capabilities are only checked if the uid/guid check fail, in which case the task will need these capabilities to access the file
> 
>     ie. if you own the file you don't need CAP_DAC_OVERRIDE
>         if you are in a group that allows access to the file you don't need CAP_DAC_OVERRIDE
> 
>     > Can you please explain the relation between DAC, apparmor and linux capability with this context?
>     >
> 
>     Its generally follows the pattern outlined in the pseudo code above, but the pattern does vary with the hook and object. The reality is more complicated than the pseudo code.
> 
>     There are hooks where you get multiple DAC checks (uid and cap) an multiple LSM checks. Eg. some file operations will be closer to the pattern
> 
>       input validation
> 
>       object lookup
>          loop on path elements
>             DAC uid check
>                DAC capability check
>                   MAC capability check
>          MAC inode check
> 
>       MAC path check
> 
>       MAC inode check
> 
> 
>     so there are potentially checks on every element of the path walk, and also checks at the operation type (eg. mmap, chown, ...)
> 
> 
> 
>     > Thanks
>     > Murali.S
>     >
>     > On Tue, Aug 4, 2020 at 6:08 AM John Johansen <john.johansen at canonical.com <mailto:john.johansen at canonical.com> <mailto:john.johansen at canonical.com <mailto:john.johansen at canonical.com>>> wrote:
>     >
>     >     On 8/3/20 8:02 PM, Murali Selvaraj wrote:
>     >     >
>     >     > Hi Seth,
>     >     >
>     >     > Thanks for the detailed explanation. Please go through below details and clarify further queries.
>     >     >
>     >     > I do not see a capability difference when this script runs in root (UID:0)  and nobody (UID>0).
>     >     > If we are observing the required capabilities when the script runs in root, that would be easy for us to find
>     >     > the needed capabilities for this script. Then we will apply this capability when it runs in nobody user.
>     >     >
>     >     > #!/bin/sh
>     >     > echo "Testing"
>     >     > while [ 1 ]
>     >     > do
>     >     > cat /etc/foo   =================> Ensure this file belongs to root permission
>     >     > echo "TESTING" > /nvram/foo
>     >     > killall <root_process_name>
>     >     > sleep 5
>     >     > done
>     >     >
>     >     >  ls -ltr /etc/foo
>     >     > -rw-r--r--    1 root     root             8 Aug  3 20:31 /etc/foo
>     >     >
>     >
>     >     can you please add
>     >
>     >     echo -n "Confinement:"
>     >     cat /proc/self/attr/current || echo "Failed to obtain confinement" ; exit 1
>     >
>     >     to your script after the killall or something similar, this will dump the confinement of the "cat" command but unless you have a transition for "cat" it should have the confinement of it parent or be denied.
>     >
>     >     I should note that apparmor does have a dedup cache around logging capabilities. It is a single entry per processor (or virtual processor), and will prevent a previously seen cap from being logged IFF no other PROFILE has mediated a cap on that processor since the last time that profile previously logged the CAP in question.
>     >
>     >     There is no manual switch to clear the cache, but it can be effectively cleared by replacing the profile but you need to actually make a change to the profile so that profile load dedup doesn't drop the replacement.
>     >
>     >
>     >     >
>     >     > Can you please check this script in your environment and share your observation. Please do the needful.
>     >     > Please execute in root and non-root mode and find the capability list from apparmor log events.
>     >     >
>     >
>     >     not exactly your script but roughly equivalent
>     >
>     >     unconfined non-root user killing root process
>     >
>     >       $ kill 23579
>     >       bash: kill: (23579) - Operation not permitted
>     >
>     >     no apparmor log message.
>     >
>     >     ----
>     >
>     >     unconfined root user killing root process
>     >
>     >       $ sudo kill 23579
>     >
>     >     success, no apparmor log message
>     >
>     >     ----
>     >
>     >     confined non-root user without signal or CAP permissions killing root process
>     >
>     >       $ aa-exec -p demo -- kill 23965
>     >       kill: (23965): Operation not permitted
>     >
>     >     no apparmor log message
>     >
>     >     ----
>     >
>     >     confined root user without signal or CAP permissions killing root process
>     >
>     >       $ sudo aa-exec -p demo -- kill 23965
>     >       kill: (23965): Permission denied
>     >
>     >     apparmor log messages
>     >
>     >     [987021.379719] audit: type=1400 audit(1596533293.878:234): apparmor="DENIED" operation="signal" profile="demo" pid=24036 comm="kill" requested_mask="send" denied_mask="send" signal=term peer="/usr/bin/man"
>     >     [987021.379727] audit: type=1400 audit(1596533293.878:235): apparmor="DENIED" operation="signal" profile="/usr/bin/man" pid=24036 comm="kill" requested_mask="receive" denied_mask="receive" signal=term peer="demo"
>     >
>     >     notice no capabilities are needed to send the signal because its being sent from root to a root process
>     >
>     >     ----
>     >
>     >     confined root user without signal or CAP permission kill a non-root process (different uids)
>     >
>     >       $ sudo aa-exec -p demo -- kill 24690
>     >       kill: (24690): Operation not permitted
>     >
>     >     apparmor log message
>     >
>     >     [989073.431936] audit: type=1400 audit(1596535345.981:238): apparmor="DENIED" operation="capable" profile="demo" pid=24717 comm="kill" capability=5  capname="kill"
>     >
>     >     finally we get a CAP request for kill
>     >
>     >
>     >     The reason for this is that the kernel applies DAC mediation before LSM (apparmor) mediation. AppArmor never sees the permission request unless DAC allow the operation.
>     >
>     >     > *Need further clarifications:*
>     >     >
>     >     > My aim is to identify the required capabilities for the process when it runs in "non-root" user.
>     >     > Currently, this process runs in root mode, so by default all CAPs are enabled in Effective/Permitted CAPs.
>     >     >
>     >     > Analysis:
>     >     >
>     >     > -> While the process runs in non-root mode, we are planning to apply the capabilities before switching to non-root from root.
>     >     >    So, we need to set appropriate capabilities in order to run the application successfully in "non-root".
>     >     >
>     >     yes
>     >
>     >     > -> As per my assumption, we will find the required capabilities when the process runs in root-mode. To find the required CAPs list
>     >     >    we thought to use "apparmor" logs while the process runs in compliant mode.
>     >
>     >     this doesn't quite work but you will be able to collect capabilities that don't rely on a uid check. This is because of how the kernel doesn't always apply a capability check, Eg. for kill CAPS are not always checked in the same way when subject uid == object uid vs. subject uid != object uid. The same can be said for DAC_OVERRIDE, DAC_READSEARCH, ...
>     >
>     >     Some capabilities however aren't guarded by uid checks and you should be able to collect these caps when run as root. What you need to do to collect the full list of capabilities is give the non-root process all capabilities and run it. This should collect the full set of CAPs with how you are using uids.
>     >
>     >
>     >     >    Once we get the CAPs list from Apparmor logs, then we shall use the same required CAPS only ( NOT all the CAPs) for the
>     >     >    process when it runs in non-root mode.
>     >     >
>     >     > -> The idea is that we are trying to drop root privilege using this method.
>     >     >
>     >     > Can you please confirm , the above method is possible in apparmor event logs to find the required CAPs at least when run
>     >     > in "root" mode.
>     >     >
>     >
>     >     close but see above, also you need to make sure exercise the application to get proper coverage
>     >
>     >     > Thanks
>     >     > Murali.S
>     >     >
>     >     > On Mon, Aug 3, 2020 at 8:21 PM Seth Arnold <seth.arnold at canonical.com <mailto:seth.arnold at canonical.com> <mailto:seth.arnold at canonical.com <mailto:seth.arnold at canonical.com>> <mailto:seth.arnold at canonical.com <mailto:seth.arnold at canonical.com> <mailto:seth.arnold at canonical.com <mailto:seth.arnold at canonical.com>>>> wrote:
>     >     >
>     >     >     Hello Murali,
>     >     >
>     >     >     On Mon, Aug 03, 2020 at 02:03:38PM -0400, Murali Selvaraj wrote:
>     >     >     > Query 1:
>     >     >     >
>     >     >     > - But I do not see CAP_DAC_OVERRIDE and CAP_KILL in apparmor event logs.
>     >     >
>     >     >     AppArmor does not have a mechanism to grant capabilities that a process
>     >     >     does not already have. The kernel will query LSMs to see if a capability
>     >     >     is allowed to be used if the process already has the capability in
>     >     >     question. (There may be exceptions to this, there's hundreds of these
>     >     >     checks scattered throughout the kernel.)
>     >     >
>     >     >     You'll only see these requests in AppArmor logs if the process had these
>     >     >     capabilities. By using su to switch to the 'nobody' account, you only have
>     >     >     access to whatever privileges the nobody account already has: additional
>     >     >     access to root_squashed files on NFS, any other processes mistakenly
>     >     >     running as user nobody, etc.
>     >     >
>     >     >     Because this doesn't include any capabilities in the process's
>     >     >     capabilities sets, AppArmor won't even see the requests.
>     >     >
>     >     >     > Query 2:
>     >     >     >
>     >     >     > - How apparmor identities how many capabilities are needed for the process?
>     >     >
>     >     >     The kernel will call capable() in the codepaths as necessary; the security
>     >     >     module interface will get the calls, without context, after the rest of
>     >     >     the kernel's capabilities handling. It's difficult to follow because it's
>     >     >     been heavily optimized for performance.
>     >     >
>     >     >     In any event, AppArmor will usually see capability requests after the
>     >     >     usual DAC permissions are handled.
>     >     >
>     >     >
>     >     >     > Query 3:
>     >     >     >
>     >     >     > - Does all system calls need capability when it runs in a non-root process,
>     >     >     > how does apparmor mapping the linux capabilities?
>     >     >
>     >     >     "root processes" means both uid 0 as well as having capabilities in the
>     >     >     effective capability set. (Perhaps it'd also make sense to consider the
>     >     >     other capability sets in the process?) A uid 0 process with no
>     >     >     capabilities still has considerable power, since many important files like
>     >     >     /etc/sudoers are owned by uid 0, and modifying these files through DAC
>     >     >     permissions alone could be used to then gain capabilities. However, a uid
>     >     >     0 process with no capabilities couldn't itself initiate a reboot in the
>     >     >     kernel, or override DAC restrictions on files, etc.
>     >     >
>     >     >     A process with capabilities need not be uid 0 though I can't immediately
>     >     >     point any common examples.
>     >     >
>     >     >     Linux's uid namespaces makes things a bit more complicated: a process can
>     >     >     have namespace-level capabilities that do not extend to capabilities in
>     >     >     the init namespace. (Consider something like an LXD guest: there may be
>     >     >     different users within the guest, and the 'root' user with the LXD guest
>     >     >     can do privileged operations over the namespace, eg manage the routing
>     >     >     table used for that network namespace, but not be able to manage the
>     >     >     routing table used by the network namespace for the init process.)
>     >     >
>     >     >     See the user_namespaces(7) and unshare(2) manpages for some more information.
>     >     >
>     >     >     > Can someone please clarify these queries?
>     >     >
>     >     >     I'm afraid my description probably made things worse.
>     >     >
>     >     >     Let me try one quick simple thing:
>     >     >
>     >     >     Run your example with and without root privileges. You'll see the
>     >     >     difference in AppArmor log output. Hopefully that helps. :)
>     >     >
>     >     >     Thanks
>     >     >
>     >     >
>     >
> 




More information about the AppArmor mailing list