]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lsm/apparmor.c
Merge pull request #408 from yosida95/patch-1
[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 #include <sys/vfs.h>
30
31 #include "log.h"
32 #include "lsm/lsm.h"
33 #include "conf.h"
34
35 lxc_log_define(lxc_apparmor, lxc);
36
37 /* set by lsm_apparmor_drv_init if true */
38 static int aa_enabled = 0;
39
40 static int mount_features_enabled = 0;
41
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"
45
46 static bool check_mount_feature_enabled(void)
47 {
48 return mount_features_enabled == 1;
49 }
50
51 static void load_mount_features_enabled(void)
52 {
53 struct stat statbuf;
54 int ret;
55
56 ret = stat(AA_MOUNT_RESTR, &statbuf);
57 if (ret == 0)
58 mount_features_enabled = 1;
59 }
60
61 /* aa_getcon is not working right now. Use our hand-rolled version below */
62 static int apparmor_enabled(void)
63 {
64 FILE *fin;
65 char e;
66 int ret;
67
68 fin = fopen(AA_ENABLED_FILE, "r");
69 if (!fin)
70 return 0;
71 ret = fscanf(fin, "%c", &e);
72 fclose(fin);
73 if (ret == 1 && e == 'Y') {
74 load_mount_features_enabled();
75 return 1;
76 }
77
78 return 0;
79 }
80
81 static char *apparmor_process_label_get(pid_t pid)
82 {
83 char path[100], *space;
84 int ret;
85 char *buf = NULL, *newbuf;
86 int sz = 0;
87 FILE *f;
88
89 ret = snprintf(path, 100, "/proc/%d/attr/current", pid);
90 if (ret < 0 || ret >= 100) {
91 ERROR("path name too long");
92 return NULL;
93 }
94 again:
95 f = fopen(path, "r");
96 if (!f) {
97 SYSERROR("opening %s", path);
98 free(buf);
99 return NULL;
100 }
101 sz += 1024;
102 newbuf = realloc(buf, sz);
103 if (!newbuf) {
104 free(buf);
105 ERROR("out of memory");
106 fclose(f);
107 return NULL;
108 }
109 buf = newbuf;
110 memset(buf, 0, sz);
111 ret = fread(buf, 1, sz - 1, f);
112 fclose(f);
113 if (ret < 0) {
114 ERROR("reading %s", path);
115 free(buf);
116 return NULL;
117 }
118 if (ret >= sz)
119 goto again;
120 space = index(buf, '\n');
121 if (space)
122 *space = '\0';
123 space = index(buf, ' ');
124 if (space)
125 *space = '\0';
126 return buf;
127 }
128
129 static int apparmor_am_unconfined(void)
130 {
131 char *p = apparmor_process_label_get(getpid());
132 int ret = 0;
133 if (!p || strcmp(p, "unconfined") == 0)
134 ret = 1;
135 free(p);
136 return ret;
137 }
138
139 /*
140 * apparmor_process_label_set: Set AppArmor process profile
141 *
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
146 *
147 * Returns 0 on success, < 0 on failure
148 *
149 * Notes: This relies on /proc being available.
150 */
151 static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf,
152 int use_default, int on_exec)
153 {
154 const char *label = inlabel ? inlabel : conf->lsm_aa_profile;
155
156 if (!aa_enabled)
157 return 0;
158
159 if (!label) {
160 if (use_default)
161 label = AA_DEF_PROFILE;
162 else
163 label = "unconfined";
164 }
165
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");
172 return -1;
173 }
174 }
175
176
177 if (strcmp(label, "unconfined") == 0 && apparmor_am_unconfined()) {
178 INFO("apparmor profile unchanged");
179 return 0;
180 }
181
182 if (aa_change_profile(label) < 0) {
183 SYSERROR("failed to change apparmor profile to %s", label);
184 return -1;
185 }
186
187 INFO("changed apparmor profile to %s", label);
188 return 0;
189 }
190
191 static struct lsm_drv apparmor_drv = {
192 .name = "AppArmor",
193 .enabled = apparmor_enabled,
194 .process_label_get = apparmor_process_label_get,
195 .process_label_set = apparmor_process_label_set,
196 };
197
198 struct lsm_drv *lsm_apparmor_drv_init(void)
199 {
200 if (!apparmor_enabled())
201 return NULL;
202 aa_enabled = 1;
203 return &apparmor_drv;
204 }