Writing the profile to /etc/apparmor.d, while also manually loading it
into the kernel results in quite a bit of confusion. In addition, it
means that people using apparmor but have /etc mounted read-only cannot
use apparmor at all on a Docker host.
Fix this by writing the profile to a temporary directory and deleting it
after it's been inserted.
Signed-off-by: Aleksa Sarai <asarai@suse.de>
| ... | ... |
@@ -23,10 +23,10 @@ func GetVersion() (int, error) {
|
| 23 | 23 |
return parseVersion(output) |
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 |
-// LoadProfile runs `apparmor_parser -r -W` on a specified apparmor profile to |
|
| 27 |
-// replace and write it to disk. |
|
| 26 |
+// LoadProfile runs `apparmor_parser -r` on a specified apparmor profile to |
|
| 27 |
+// replace the profile. |
|
| 28 | 28 |
func LoadProfile(profilePath string) error {
|
| 29 |
- _, err := cmd(filepath.Dir(profilePath), "-r", "-W", filepath.Base(profilePath)) |
|
| 29 |
+ _, err := cmd("-r", filepath.Dir(profilePath))
|
|
| 30 | 30 |
if err != nil {
|
| 31 | 31 |
return err |
| 32 | 32 |
} |
| ... | ... |
@@ -5,6 +5,7 @@ package apparmor |
| 5 | 5 |
import ( |
| 6 | 6 |
"bufio" |
| 7 | 7 |
"io" |
| 8 |
+ "io/ioutil" |
|
| 8 | 9 |
"os" |
| 9 | 10 |
"path" |
| 10 | 11 |
"strings" |
| ... | ... |
@@ -16,8 +17,6 @@ import ( |
| 16 | 16 |
var ( |
| 17 | 17 |
// profileDirectory is the file store for apparmor profiles and macros. |
| 18 | 18 |
profileDirectory = "/etc/apparmor.d" |
| 19 |
- // defaultProfilePath is the default path for the apparmor profile to be saved. |
|
| 20 |
- defaultProfilePath = path.Join(profileDirectory, "docker") |
|
| 21 | 19 |
) |
| 22 | 20 |
|
| 23 | 21 |
// profileData holds information about the given profile for generation. |
| ... | ... |
@@ -70,26 +69,26 @@ func macroExists(m string) bool {
|
| 70 | 70 |
// InstallDefault generates a default profile and installs it in the |
| 71 | 71 |
// ProfileDirectory with `apparmor_parser`. |
| 72 | 72 |
func InstallDefault(name string) error {
|
| 73 |
- // Make sure the path where they want to save the profile exists |
|
| 74 |
- if err := os.MkdirAll(profileDirectory, 0755); err != nil {
|
|
| 75 |
- return err |
|
| 76 |
- } |
|
| 77 |
- |
|
| 78 | 73 |
p := profileData{
|
| 79 | 74 |
Name: name, |
| 80 | 75 |
} |
| 81 | 76 |
|
| 82 |
- f, err := os.OpenFile(defaultProfilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) |
|
| 77 |
+ // Install to a temporary directory. |
|
| 78 |
+ f, err := ioutil.TempFile("", name)
|
|
| 83 | 79 |
if err != nil {
|
| 84 | 80 |
return err |
| 85 | 81 |
} |
| 82 |
+ profilePath := f.Name() |
|
| 83 |
+ |
|
| 84 |
+ defer f.Close() |
|
| 85 |
+ defer os.Remove(profilePath) |
|
| 86 |
+ |
|
| 86 | 87 |
if err := p.generateDefault(f); err != nil {
|
| 87 | 88 |
f.Close() |
| 88 | 89 |
return err |
| 89 | 90 |
} |
| 90 |
- f.Close() |
|
| 91 | 91 |
|
| 92 |
- if err := aaparser.LoadProfile(defaultProfilePath); err != nil {
|
|
| 92 |
+ if err := aaparser.LoadProfile(profilePath); err != nil {
|
|
| 93 | 93 |
return err |
| 94 | 94 |
} |
| 95 | 95 |
|