]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lsm/apparmor.c
apparmor: don't do on-exec profile changes
[mirror_lxc.git] / src / lxc / lsm / apparmor.c
1 /* apparmor
2 *
3 * Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2012 Canonical Ltd.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/mount.h>
28 #include <sys/apparmor.h>
29
30 #include "log.h"
31 #include "lsm/lsm.h"
32
33 lxc_log_define(lxc_apparmor, lxc);
34
35 /* set by lsm_apparmor_drv_init if true */
36 static int aa_enabled = 0;
37
38 #define AA_DEF_PROFILE "lxc-container-default"
39 #define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask"
40 #define AA_ENABLED_FILE "/sys/module/apparmor/parameters/enabled"
41
42 /* aa_getcon is not working right now. Use our hand-rolled version below */
43 static int apparmor_enabled(void)
44 {
45 struct stat statbuf;
46 FILE *fin;
47 char e;
48 int ret;
49
50 ret = stat(AA_MOUNT_RESTR, &statbuf);
51 if (ret != 0)
52 return 0;
53 fin = fopen(AA_ENABLED_FILE, "r");
54 if (!fin)
55 return 0;
56 ret = fscanf(fin, "%c", &e);
57 fclose(fin);
58 if (ret == 1 && e == 'Y')
59 return 1;
60 return 0;
61 }
62
63 static char *apparmor_process_label_get(pid_t pid)
64 {
65 char path[100], *space;
66 int ret;
67 char *buf = NULL, *newbuf;
68 int sz = 0;
69 FILE *f;
70
71 ret = snprintf(path, 100, "/proc/%d/attr/current", pid);
72 if (ret < 0 || ret >= 100) {
73 ERROR("path name too long");
74 return NULL;
75 }
76 again:
77 f = fopen(path, "r");
78 if (!f) {
79 SYSERROR("opening %s", path);
80 if (buf)
81 free(buf);
82 return NULL;
83 }
84 sz += 1024;
85 newbuf = realloc(buf, sz);
86 if (!newbuf) {
87 free(buf);
88 ERROR("out of memory");
89 fclose(f);
90 return NULL;
91 }
92 buf = newbuf;
93 memset(buf, 0, sz);
94 ret = fread(buf, 1, sz - 1, f);
95 fclose(f);
96 if (ret < 0) {
97 ERROR("reading %s", path);
98 free(buf);
99 return NULL;
100 }
101 if (ret >= sz)
102 goto again;
103 space = index(buf, '\n');
104 if (space)
105 *space = '\0';
106 space = index(buf, ' ');
107 if (space)
108 *space = '\0';
109 return buf;
110 }
111
112 static int apparmor_am_unconfined(void)
113 {
114 char *p = apparmor_process_label_get(getpid());
115 int ret = 0;
116 if (!p || strcmp(p, "unconfined") == 0)
117 ret = 1;
118 if (p)
119 free(p);
120 return ret;
121 }
122
123 /*
124 * apparmor_process_label_set: Set AppArmor process profile
125 *
126 * @label : the profile to set
127 * @default : use the default profile if label is NULL
128 * @on_exec : this is ignored. Apparmor profile will be changed immediately
129 *
130 * Returns 0 on success, < 0 on failure
131 *
132 * Notes: This relies on /proc being available.
133 */
134 static int apparmor_process_label_set(const char *label, int use_default,
135 int on_exec)
136 {
137 if (!aa_enabled)
138 return 0;
139
140 if (!label) {
141 if (use_default)
142 label = AA_DEF_PROFILE;
143 else
144 return 0;
145 }
146
147 if (strcmp(label, "unconfined") == 0 && apparmor_am_unconfined()) {
148 INFO("apparmor profile unchanged");
149 return 0;
150 }
151
152 if (aa_change_profile(label) < 0) {
153 SYSERROR("failed to change apparmor profile to %s", label);
154 return -1;
155 }
156
157 INFO("changed apparmor profile to %s", label);
158 return 0;
159 }
160
161 static struct lsm_drv apparmor_drv = {
162 .name = "AppArmor",
163 .enabled = apparmor_enabled,
164 .process_label_get = apparmor_process_label_get,
165 .process_label_set = apparmor_process_label_set,
166 };
167
168 struct lsm_drv *lsm_apparmor_drv_init(void)
169 {
170 if (!apparmor_enabled())
171 return NULL;
172 aa_enabled = 1;
173 return &apparmor_drv;
174 }