Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. |
Customizing AppArmor Profiles for ROS
Description: This tutorial explains how to customizing AppArmor Profiles to be used for securing ROS.Keywords: SROS, AppArmor, Linux Security Module
Tutorial Level: INTERMEDIATE
If you are new to AppArmor: You may find it helpful to first read an introduction on AppArmor and Mandatory Access Control based profiles. A quick guide to the profile lanuage can be found here, and a more general list of getting started documentation can be found here.
Now that we have the policy profile library for ROS installed, we have all the building blocks we need to build our own policprovile for our custom ROS application. Once you have one written, you can save it to your systems configuration directory for AppArmor, /etc/apparmor.d/, then reload AppArmor to have the changes take effect. For this example, we'll use the traditional talker/listener ros launch example. Let's work our way through the profile file:
1 #include <tunables/global>
2 #include <tunables/ros>
3
4 profile ros/roslaunch @{ROS_INSTALL_BIN}/{,s}roslaunch {
5 #include <ros/nodes/roslaunch>
6
7 @{ROS_INSTALL_BIN}/roslaunch rix,
8 }
9
10 profile ros/rosmaster @{ROS_INSTALL_BIN}/rosmaster {
11 #include <ros/base>
12 #include <ros/node>
13 #include <ros/python>
14
15 @{ROS_INSTALL_BIN}/rosmaster rix,
16 }
17
18 profile ros/roscore @{ROS_INSTALL_BIN}/{,s}roscore {
19 #include <ros/nodes/roslaunch>
20
21 @{HOME}/.rnd r,
22 @{ROS_INSTALL_BIN}/roslaunch rix,
23 @{ROS_INSTALL_BIN}/{,s}roscore rix,
24 }
25
26 profile ros/rosout @{ROS_INSTALL_LIB}/rosout/* {
27 #include <ros/base>
28 #include <ros/node>
29
30 @{ROS_INSTALL_LIB}/rosout/rosout rix,
31 }
32
33 profile ros/talker_listener_py @{ROS_INSTALL_SHARE}/rospy_tutorials/001_talker_listener/{talker,listener}* {
34 #include <ros/base>
35 #include <ros/node>
36 #include <ros/python>
37
38 @{ROS_INSTALL_SHARE}/rospy_tutorials/001_talker_listener/talker.py r,
39 @{ROS_INSTALL_SHARE}/rospy_tutorials/001_talker_listener/listener.py r,
40 }
41
42 profile ros/talker_listener_cpp @{ROS_INSTALL_LIB}/roscpp_tutorials/{talker,listener}* {
43 #include <ros/base>command
44 #include <ros/node>
45
46 @{ROS_INSTALL_LIB}/roscpp_tutorials/listener rix,
47 @{ROS_INSTALL_LIB}/roscpp_tutorials/talker rix,
48 }
Let's go over this in a little more detail.
We'll need to include some essential attributes necessary for ROS; this enatils many covenant global abstractions such as home directory and common aliases, then also abstractions that are ROS specific such as variables defining ROS_HOME, ROS_ROOT annd ect...
Now we can define our first profile section for roslaunch. This executable requires some additional permissions in order to enable roslaunch to function normally, e.g. utilized shell enfoments to launch nodes, send signals child nodes to stop, adapt ldconfig for node runtimes. All necessary permissions are included through the specified subprofile, and then the roslaunch made executable, inheriting the current profile.
For this profile section, we'll make the allowances for rosmaster. This is also a python based executable, so in addition to the base abstractions of being able to receive signals and signal itself, and the node abstractions of being able to read shared ROS libraries, we also include abstractions that are python specific.
The profile section for roscore is much the same as that for roslaunch, as roscore mainly uses roslaunch under the hood to bootstrap and launch fundamental ROS services. Take note on how both the attachment specification and the executable path make use of the globbing syntax, {,s}, to abstract the policy coverage to encompass both original and secure implementations.
The profile section for rosout, as seen from the attachment specification is generalised for all things under rosout, where in particular, only the rosout binary is made executable within that profile. Because rosout is a simple C++ node, it only requires the base and node abstractions.
33 profile ros/talker_listener_py @{ROS_INSTALL_SHARE}/rospy_tutorials/001_talker_listener/{talker,listener}* {
34 #include <ros/base>
35 #include <ros/node>
36 #include <ros/python>
37
38 @{ROS_INSTALL_SHARE}/rospy_tutorials/001_talker_listener/talker.py r,
39 @{ROS_INSTALL_SHARE}/rospy_tutorials/001_talker_listener/listener.py r,
40 }
41
42 profile ros/talker_listener_cpp @{ROS_INSTALL_LIB}/roscpp_tutorials/{talker,listener}* {
43 #include <ros/base>command
44 #include <ros/node>
45
46 @{ROS_INSTALL_LIB}/roscpp_tutorials/listener rix,
47 @{ROS_INSTALL_LIB}/roscpp_tutorials/talker rix,
48 }
These last two profile sections are custom to the Python and C++ node implementations of the talker and listener examples. Here in the attachment specification we again use globbing, {talker,listener}*, to capture both scripts, binary files and links with the common name, and then define an appropriate policy pertinent to Python's or C++'s runtime behavior.