3 * Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2012 Canonical Ltd.
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.
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.
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
25 #include <sys/types.h>
27 #include <sys/mount.h>
28 #include <sys/apparmor.h>
35 lxc_log_define(lxc_apparmor
, lxc
);
37 /* set by lsm_apparmor_drv_init if true */
38 static int aa_enabled
= 0;
40 static int mount_features_enabled
= 0;
42 #define AA_DEF_PROFILE "lxc-container-default"
43 #define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask"
44 #define AA_ENABLED_FILE "/sys/module/apparmor/parameters/enabled"
46 static bool check_mount_feature_enabled(void)
48 return mount_features_enabled
== 1;
51 static void load_mount_features_enabled(void)
56 ret
= stat(AA_MOUNT_RESTR
, &statbuf
);
58 mount_features_enabled
= 1;
61 /* aa_getcon is not working right now. Use our hand-rolled version below */
62 static int apparmor_enabled(void)
68 fin
= fopen(AA_ENABLED_FILE
, "r");
71 ret
= fscanf(fin
, "%c", &e
);
73 if (ret
== 1 && e
== 'Y') {
74 load_mount_features_enabled();
81 static char *apparmor_process_label_get(pid_t pid
)
83 char path
[100], *space
;
85 char *buf
= NULL
, *newbuf
;
89 ret
= snprintf(path
, 100, "/proc/%d/attr/current", pid
);
90 if (ret
< 0 || ret
>= 100) {
91 ERROR("path name too long");
97 SYSERROR("opening %s", path
);
102 newbuf
= realloc(buf
, sz
);
105 ERROR("out of memory");
111 ret
= fread(buf
, 1, sz
- 1, f
);
114 ERROR("reading %s", path
);
120 space
= index(buf
, '\n');
123 space
= index(buf
, ' ');
129 static int apparmor_am_unconfined(void)
131 char *p
= apparmor_process_label_get(getpid());
133 if (!p
|| strcmp(p
, "unconfined") == 0)
140 * apparmor_process_label_set: Set AppArmor process profile
142 * @label : the profile to set
143 * @conf : the container configuration to use @label is NULL
144 * @default : use the default profile if label is NULL
145 * @on_exec : this is ignored. Apparmor profile will be changed immediately
147 * Returns 0 on success, < 0 on failure
149 * Notes: This relies on /proc being available.
151 static int apparmor_process_label_set(const char *inlabel
, struct lxc_conf
*conf
,
152 int use_default
, int on_exec
)
154 const char *label
= inlabel
? inlabel
: conf
->lsm_aa_profile
;
161 label
= AA_DEF_PROFILE
;
163 label
= "unconfined";
166 if (!check_mount_feature_enabled() && strcmp(label
, "unconfined") != 0) {
167 WARN("Incomplete AppArmor support in your kernel");
168 if (!conf
->lsm_aa_allow_incomplete
) {
169 ERROR("If you really want to start this container, set");
170 ERROR("lxc.aa_allow_incomplete = 1");
171 ERROR("in your container configuration file");
177 if (strcmp(label
, "unconfined") == 0 && apparmor_am_unconfined()) {
178 INFO("apparmor profile unchanged");
182 if (aa_change_profile(label
) < 0) {
183 SYSERROR("failed to change apparmor profile to %s", label
);
187 INFO("changed apparmor profile to %s", label
);
191 static struct lsm_drv apparmor_drv
= {
193 .enabled
= apparmor_enabled
,
194 .process_label_get
= apparmor_process_label_get
,
195 .process_label_set
= apparmor_process_label_set
,
198 struct lsm_drv
*lsm_apparmor_drv_init(void)
200 if (!apparmor_enabled())
203 return &apparmor_drv
;