Skip to content
Snippets Groups Projects
Commit 15e22a4b authored by Elvstam Cantner Andreas's avatar Elvstam Cantner Andreas
Browse files

Add secton resource limits to AppArmor guideline


Signed-off-by: default avatarSamir Jasarevic <samir.jasarevic@se.bosch.com>
parent a3f513d2
No related branches found
No related tags found
1 merge request!208Add new version of AppArmor guide
......@@ -438,6 +438,162 @@ will only have a sub-set of the rules in the common file since a deny rule is ad
to override one of the rules from the common file to deny read access to any `.h`
file in `/usr/include/`.
## File access
Since the AppArmor security model is a MAC implementation, it can only confine access to resources that the executable’s owner already has access to, according to the DAC access permission rules.
As an example, the diagram below shows the contents of `/home/user` directory and the files’ owner, which is "user", has read/write access to the first three files in the green DAC box. On the other hand, the owner "user" does not have acces to the last file, as defined by the DAC permission rules.
![](/images/MAC-DAC-example.png)
AppArmor can only create permission rules to the files in the green DAC box, and cannot give more access than what is already accessible for "user". In this example, AppArmor could create rules for an executable owned by "user" that allows **read only** access to **only** two files, i.e. files within the purple MAC box. Despite the fact that "user" would normally be able to have both read/write permissions on all three files in the green DAC box, in this case, the access would be denied to the first file due to confinement by AppArmor. In the table below, it is shown what access an executable owned by "user" would have before and after AppArmor access rules are applied.
| Files in "user" directory | Access given by DAC | Access given by MAC / AppArmor |
| :--------: | :-----: | :-----: |
| file_1.txt | **Yes** | No |
| file_2.txt | **Yes** | **Yes** |
| file_3.txt | **Yes** | **Yes** |
| file_4.txt | No | No |
Based on the above example of DAC and MAC access permissions, the following bash script reads two files that the script’s owner has access to and nothing else. Note that the script does not need to write anything to the files, even though the user could do that.
In order to achieve the desired behavior an AppArmor profile for the executable needs to be created using the `aa-genprof` tool. Before running the `aa-genprof` tool, make sure the file_access.sh script has execute permission for the owner.
Below is the content of the directory with four text files and the bash script. There is also content of the bash script / executable (file_access.sh) and the created profile (home.user.file_access.sh).
Listed files in the `/home/user` directory:
$ ls -al /home/user
-rw-r--r-- user grp … file_1.txt
-rw-r--r-- user grp … file_2.txt
-rw-r--r-- user grp … file_3.txt
-rw-r--r-- usr2 gr2 … file_4.txt
-rwxr--r-- user grp … file_access.sh
Below is the content of `file_access.sh`:
#!/bin/bash
cat file_2.txt
cat file_3.txt
Below is the content of `/etc/apparmor.d/home.user.file_access.sh`:
#include <tunables/global>
/home/user/file_access.sh {
#include <abstractions/base>
#include <abstractions/bash>
#include <abstractions/consoles>
/home/user/files_access.sh r,
/usr/bin/bash ix,
/usr/bin/cat mrix,
owner /home/*/file_2.txt r,
owner /home/*/file_3.txt r,
}
Description of the above profile:
- #include <tunables/global> : Includes statements from other files, so there is no need to duplicate the common rules.
- /home/user/file_access.sh : Path to the profiled executable.
- #include <abstractions/*> : Includes common variables and libraries.
- /home/user/files_access.sh r, : Allows the read access to the files_access.sh script.
- /usr/bin/bash ix, : Inherit execute, i.e. the executed bash program will inherit the current profile.
- /usr/bin/cat mrix , : Allows the cat application read and write access to a file mapped in memory. Also, inherits the current profile.
- owner /home/*/file_2.txt r, : Allows the read access to file_2.txt, which could be placed in any directory under /home/ owned by the owner.
When the `file_access.sh` script is run by "user", it will show the content of the two files that "user" has read permissions for in the created profile.
Now we change the `file_access.sh` to include reading of two additional files, the one that the user has access to (file_1.txt) and the one that the user doesn’t have access to (file_4.txt), according to the DAC permission rules. After the change, the executable should look like this:
Below is the content of updated `file_access.sh`:
#!/bin/bash
cat file_1.txt
cat file_2.txt
cat file_3.txt
cat file_4.txt
When the updated script above is run again, AppArmor (assuming it is in enforce mode) will deny access to the both newly added files. The reason is simply because the profile of the executable has not been updated. The profile only allows read access to the files mentioned in the profile, i.e. file_2.txt and file_3.txt, and everything else will be implicitly denied. If we would add read access to file_1.txt and file_4.txt to the existing profile, i.e. same as for the other two files, the result this time would be that reading of all files, except the file_4.txt file, would be allowed. The access to the file_4.txt file would still be denied, because the owner of the executable does not have access to that file. In this case, the DAC read permission rule would kick in and deny the access, and as we already know, AppArmor cannot grant more permissions than the owner of the executable already has.
## Resource limit control
One of the important confinement possibilities with AppArmor is also resource limitations that can be set and controlled in profiles. Following are examples of resources that can be limited: maximum size of process’s memory, maximum CPU time, maximum size of files that a process may create, maximum size of memory that may be allocated in RAM, maximum number of processes that can be created by the calling process etc.
The resource limitations are handled with kernel’s rlimits, which are also known as ulimits. According to the excerpt from the [getrlimit(2)](https://man7.org/linux/man-pages/man2/prlimit.2.html) Linux man page: “Each resource has an associated soft and hard limit. The soft limit is the value that the kernel enforces for the corresponding resource. The hard limit acts as a ceiling for the soft limit: an unprivileged process may only set its soft limit to a value in the range from 0 up to the hard limit, and (irreversibly) lower its hard limit. A privileged process (under Linux: one with the `CAP_SYS_RESOURCE` capability) may make arbitrary changes to either limit value.” AppArmor can only control an executable’s hard limits and make sure the soft limits are not higher than the hard limits.
As with all other confinement possibilities AppArmor offers, it cannot raise the system’s rlimits, but only reduce what is already allowed by the system. If an executable would try to raise its hard rlimits to larger values than specified in its profile, AppArmor would prevent that. Profiles’ rlimits can only be either lower or equal to the system’s rlimits. When it comes to inheritance, a child will keep the same rlimts as its parent process and the rlimits will remain unchanged even if the executable becomes unconfined. Also, if an executable transfers to a new profile, e.g. if a new parent profile is created and the old executable becomes a child, in that new parent profile it is possible to further reduce rlimits. AppArmor does not provide any additional logging for rlimits.
The command to control the hard limit rule in AppArmor has the following syntax:
set rlimit `resource` <= `value`,
The `resource` variable could be e.g. cpu, fsize, data, stack, core, rss, nofile, ofile, as, nproc, memlock, locks etc. For complete overview of all possible variables and corresponding `values` that can be specified for the rlimit rules, please check RLIMIT RULE syntax on Ubuntu manpage [apparmor.d - syntax of security profiles for AppArmor](http://manpages.ubuntu.com/manpages/xenial/man5/apparmor.d.5.html). Currently there is no tool that will automatically write a rlimit rule to a profile, hence it always needs to be inserted manually. If an update of a profile containing rlimits is made by e.g. the aa-logprof tool, it will not do any changes to the existing rlimit rules.
To find out what soft and hard resource limits there are for a certain process, read the following file (replace PID with the real process ID number):
cat /proc/PID/limits
In the following example, where a bash script is used, a limited amount of text is written to a file. But in a real application, it could for example be a log file that the script could write to without any restrictions, and in that case a large file size could be an issue for our system. The potential issue could be made by a mistake or deliberately by an attacker.
Below is the content of `max_file_size.sh`:
```
#!/bin/bash
FILE_NAME=/home/user/file.txt
touch $FILE_NAME
> $FILE_NAME
FILE_BLOCK_SIZE=`du -b $FILE_NAME | cut -f1`
echo "Size of $FILE_NAME is $FILE_BLOCK_SIZE blocks."
# For each loop, the file is increased by 10 blocks.
# In total, the size of the file can be 50 blocks.
for ((s=0; s<5; s++))
do
echo "Some text" >> $FILE_NAME
FILE_BLOCK_SIZE=`du -b $FILE_NAME | cut -f1`
echo "Size of $FILE_NAME is $FILE_BLOCK_SIZE blocks."
done
```
In the created profile for the above script, the file size is limited to max 40 blocks, which is equivalent to 40 bytes. We already know that the above script will create a file with size of 50 blocks if there are no restrictions.
Below is the content of profile `/etc/apparmor.d/home.user.max_file_size.sh`:
```
include <tunables/global>
/home/user/max_file_size.sh {
#include <abstractions/base>
#include <abstractions/bash>
#include <abstractions/consoles>
/etc/ld.so.cache r,
/home/user/max_file_size.sh r,
/usr/bin/bash ix,
/usr/bin/cut mrix,
/usr/bin/du mrix,
/usr/bin/touch mrix,
owner /home/*/file.txt w,
# Limit the file size to max 40 blocks.
set rlimit fsize <= 40,
}
```
After putting the above profile in enforce mode and running the `max_file_size.sh` script, the following result is obtained in the console (Note: This will not be logged by AppArmor, unless audit is explicitly specified):
> ./max_file_size.sh
Size of /home/user/file.txt is 0 blocks.
Size of /home/user/file.txt is 10 blocks.
Size of /home/user/file.txt is 20 blocks.
Size of /home/user/file.txt is 30 blocks.
Size of /home/user/file.txt is 40 blocks.
File size limit exceeded (core dumped)
As seen from the above console output, the AppArmor rlimit rule kicks in and stops further writing to the file, which the script is writing to. This is a very simple and effective way to impose the file size limit to the running script that could potentially create an issue for our system if the default file size limit would be used instead.
## Capabilities
### Capabilities Introduction
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment