]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lsm/apparmor.c
Merge pull request #3343 from Blub/apparmor-mount-rule-generation
[mirror_lxc.git] / src / lxc / lsm / apparmor.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE 1
5 #endif
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/mount.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <sys/vfs.h>
13 #include <unistd.h>
14
15 #include "caps.h"
16 #include "conf.h"
17 #include "config.h"
18 #include "initutils.h"
19 #include "log.h"
20 #include "lsm.h"
21 #include "parse.h"
22 #include "raw_syscalls.h"
23 #include "utils.h"
24
25 lxc_log_define(apparmor, lsm);
26
27 /* set by lsm_apparmor_drv_init if true */
28 static int aa_enabled = 0;
29 static bool aa_parser_available = false;
30 static bool aa_supports_unix = false;
31 static bool aa_can_stack = false;
32 static bool aa_is_stacked = false;
33 static bool aa_admin = false;
34
35 static int mount_features_enabled = 0;
36
37 #define AA_DEF_PROFILE "lxc-container-default"
38 #define AA_DEF_PROFILE_CGNS "lxc-container-default-cgns"
39 #define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask"
40 #define AA_ENABLED_FILE "/sys/module/apparmor/parameters/enabled"
41 #define AA_UNCHANGED "unchanged"
42 #define AA_GENERATED "generated"
43
44 #define AA_CMD_LOAD 'r'
45 #define AA_CMD_UNLOAD 'R'
46 #define AA_CMD_PARSE 'Q'
47
48 static const char AA_PROFILE_BASE[] =
49 " ### Base profile\n"
50 " capability,\n"
51 " dbus,\n"
52 " file,\n"
53 " network,\n"
54 " umount,\n"
55 "\n"
56 " # Allow us to receive signals from anywhere.\n"
57 " signal (receive),\n"
58 "\n"
59 " # Allow us to send signals to ourselves\n"
60 " signal peer=@{profile_name},\n"
61 "\n"
62 " # Allow other processes to read our /proc entries, futexes, perf tracing and\n"
63 " # kcmp for now (they will need 'read' in the first place). Administrators can\n"
64 " # override with:\n"
65 " # deny ptrace (readby) ...\n"
66 " ptrace (readby),\n"
67 "\n"
68 " # Allow other processes to trace us by default (they will need 'trace' in\n"
69 " # the first place). Administrators can override with:\n"
70 " # deny ptrace (tracedby) ...\n"
71 " ptrace (tracedby),\n"
72 "\n"
73 " # Allow us to ptrace ourselves\n"
74 " ptrace peer=@{profile_name},\n"
75 "\n"
76 " # ignore DENIED message on / remount\n"
77 " deny mount options=(ro, remount) -> /,\n"
78 " deny mount options=(ro, remount, silent) -> /,\n"
79 "\n"
80 " # allow tmpfs mounts everywhere\n"
81 " mount fstype=tmpfs,\n"
82 "\n"
83 " # allow hugetlbfs mounts everywhere\n"
84 " mount fstype=hugetlbfs,\n"
85 "\n"
86 " # allow mqueue mounts everywhere\n"
87 " mount fstype=mqueue,\n"
88 "\n"
89 " # allow fuse mounts everywhere\n"
90 " mount fstype=fuse,\n"
91 " mount fstype=fuse.*,\n"
92 "\n"
93 " # deny access under /proc/bus to avoid e.g. messing with pci devices directly\n"
94 " deny @{PROC}/bus/** wklx,\n"
95 "\n"
96 " # deny writes in /proc/sys/fs but allow binfmt_misc to be mounted\n"
97 " mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/,\n"
98 " deny @{PROC}/sys/fs/** wklx,\n"
99 "\n"
100 " # allow efivars to be mounted, writing to it will be blocked though\n"
101 " mount fstype=efivarfs -> /sys/firmware/efi/efivars/,\n"
102 "\n"
103 " # block some other dangerous paths\n"
104 " deny @{PROC}/kcore rwklx,\n"
105 " deny @{PROC}/sysrq-trigger rwklx,\n"
106 " deny @{PROC}/acpi/** rwklx,\n"
107 "\n"
108 " # deny writes in /sys except for /sys/fs/cgroup, also allow\n"
109 " # fusectl, securityfs and debugfs to be mounted there (read-only)\n"
110 " mount fstype=fusectl -> /sys/fs/fuse/connections/,\n"
111 " mount fstype=securityfs -> /sys/kernel/security/,\n"
112 " mount fstype=debugfs -> /sys/kernel/debug/,\n"
113 " deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/,\n"
114 " mount fstype=proc -> /proc/,\n"
115 " mount fstype=sysfs -> /sys/,\n"
116 " mount options=(rw, nosuid, nodev, noexec, remount) -> /sys/,\n"
117 " deny /sys/firmware/efi/efivars/** rwklx,\n"
118 " # note, /sys/kernel/security/** handled below\n"
119 " mount options=(ro, nosuid, nodev, noexec, remount, strictatime) -> /sys/fs/cgroup/,\n"
120 "\n"
121 " # deny reads from debugfs\n"
122 " deny /sys/kernel/debug/{,**} rwklx,\n"
123 "\n"
124 " # allow paths to be made slave, shared, private or unbindable\n"
125 " # FIXME: This currently doesn't work due to the apparmor parser treating those as allowing all mounts.\n"
126 "# mount options=(rw,make-slave) -> **,\n"
127 "# mount options=(rw,make-rslave) -> **,\n"
128 "# mount options=(rw,make-shared) -> **,\n"
129 "# mount options=(rw,make-rshared) -> **,\n"
130 "# mount options=(rw,make-private) -> **,\n"
131 "# mount options=(rw,make-rprivate) -> **,\n"
132 "# mount options=(rw,make-unbindable) -> **,\n"
133 "# mount options=(rw,make-runbindable) -> **,\n"
134 "\n"
135 "# Allow limited modification of mount propagation\n"
136 " mount options=(rw,make-slave) -> /,\n"
137 " mount options=(rw,make-rslave) -> /,\n"
138 " mount options=(rw,make-shared) -> /,\n"
139 " mount options=(rw,make-rshared) -> /,\n"
140 " mount options=(rw,make-private) -> /,\n"
141 " mount options=(rw,make-rprivate) -> /,\n"
142 " mount options=(rw,make-unbindable) -> /,\n"
143 " mount options=(rw,make-runbindable) -> /,\n"
144 "\n"
145 " # allow bind-mounts of anything except /proc, /sys and /dev\n"
146 " mount options=(rw,bind) /[^spd]*{,/**},\n"
147 " mount options=(rw,bind) /d[^e]*{,/**},\n"
148 " mount options=(rw,bind) /de[^v]*{,/**},\n"
149 " mount options=(rw,bind) /dev/.[^l]*{,/**},\n"
150 " mount options=(rw,bind) /dev/.l[^x]*{,/**},\n"
151 " mount options=(rw,bind) /dev/.lx[^c]*{,/**},\n"
152 " mount options=(rw,bind) /dev/.lxc?*{,/**},\n"
153 " mount options=(rw,bind) /dev/[^.]*{,/**},\n"
154 " mount options=(rw,bind) /dev?*{,/**},\n"
155 " mount options=(rw,bind) /p[^r]*{,/**},\n"
156 " mount options=(rw,bind) /pr[^o]*{,/**},\n"
157 " mount options=(rw,bind) /pro[^c]*{,/**},\n"
158 " mount options=(rw,bind) /proc?*{,/**},\n"
159 " mount options=(rw,bind) /s[^y]*{,/**},\n"
160 " mount options=(rw,bind) /sy[^s]*{,/**},\n"
161 " mount options=(rw,bind) /sys?*{,/**},\n"
162 "\n"
163 " # Allow rbind-mounts of anything except /, /dev, /proc and /sys\n"
164 " mount options=(rw,rbind) /[^spd]*{,/**},\n"
165 " mount options=(rw,rbind) /d[^e]*{,/**},\n"
166 " mount options=(rw,rbind) /de[^v]*{,/**},\n"
167 " mount options=(rw,rbind) /dev?*{,/**},\n"
168 " mount options=(rw,rbind) /p[^r]*{,/**},\n"
169 " mount options=(rw,rbind) /pr[^o]*{,/**},\n"
170 " mount options=(rw,rbind) /pro[^c]*{,/**},\n"
171 " mount options=(rw,rbind) /proc?*{,/**},\n"
172 " mount options=(rw,rbind) /s[^y]*{,/**},\n"
173 " mount options=(rw,rbind) /sy[^s]*{,/**},\n"
174 " mount options=(rw,rbind) /sys?*{,/**},\n"
175 "\n"
176 " # allow moving mounts except for /proc, /sys and /dev\n"
177 " mount options=(rw,move) /[^spd]*{,/**},\n"
178 " mount options=(rw,move) /d[^e]*{,/**},\n"
179 " mount options=(rw,move) /de[^v]*{,/**},\n"
180 " mount options=(rw,move) /dev/.[^l]*{,/**},\n"
181 " mount options=(rw,move) /dev/.l[^x]*{,/**},\n"
182 " mount options=(rw,move) /dev/.lx[^c]*{,/**},\n"
183 " mount options=(rw,move) /dev/.lxc?*{,/**},\n"
184 " mount options=(rw,move) /dev/[^.]*{,/**},\n"
185 " mount options=(rw,move) /dev?*{,/**},\n"
186 " mount options=(rw,move) /p[^r]*{,/**},\n"
187 " mount options=(rw,move) /pr[^o]*{,/**},\n"
188 " mount options=(rw,move) /pro[^c]*{,/**},\n"
189 " mount options=(rw,move) /proc?*{,/**},\n"
190 " mount options=(rw,move) /s[^y]*{,/**},\n"
191 " mount options=(rw,move) /sy[^s]*{,/**},\n"
192 " mount options=(rw,move) /sys?*{,/**},\n"
193 "\n"
194 " # generated by: lxc-generate-aa-rules.py container-rules.base\n"
195 " deny /proc/sys/[^kn]*{,/**} wklx,\n"
196 " deny /proc/sys/k[^e]*{,/**} wklx,\n"
197 " deny /proc/sys/ke[^r]*{,/**} wklx,\n"
198 " deny /proc/sys/ker[^n]*{,/**} wklx,\n"
199 " deny /proc/sys/kern[^e]*{,/**} wklx,\n"
200 " deny /proc/sys/kerne[^l]*{,/**} wklx,\n"
201 " deny /proc/sys/kernel/[^smhd]*{,/**} wklx,\n"
202 " deny /proc/sys/kernel/d[^o]*{,/**} wklx,\n"
203 " deny /proc/sys/kernel/do[^m]*{,/**} wklx,\n"
204 " deny /proc/sys/kernel/dom[^a]*{,/**} wklx,\n"
205 " deny /proc/sys/kernel/doma[^i]*{,/**} wklx,\n"
206 " deny /proc/sys/kernel/domai[^n]*{,/**} wklx,\n"
207 " deny /proc/sys/kernel/domain[^n]*{,/**} wklx,\n"
208 " deny /proc/sys/kernel/domainn[^a]*{,/**} wklx,\n"
209 " deny /proc/sys/kernel/domainna[^m]*{,/**} wklx,\n"
210 " deny /proc/sys/kernel/domainnam[^e]*{,/**} wklx,\n"
211 " deny /proc/sys/kernel/domainname?*{,/**} wklx,\n"
212 " deny /proc/sys/kernel/h[^o]*{,/**} wklx,\n"
213 " deny /proc/sys/kernel/ho[^s]*{,/**} wklx,\n"
214 " deny /proc/sys/kernel/hos[^t]*{,/**} wklx,\n"
215 " deny /proc/sys/kernel/host[^n]*{,/**} wklx,\n"
216 " deny /proc/sys/kernel/hostn[^a]*{,/**} wklx,\n"
217 " deny /proc/sys/kernel/hostna[^m]*{,/**} wklx,\n"
218 " deny /proc/sys/kernel/hostnam[^e]*{,/**} wklx,\n"
219 " deny /proc/sys/kernel/hostname?*{,/**} wklx,\n"
220 " deny /proc/sys/kernel/m[^s]*{,/**} wklx,\n"
221 " deny /proc/sys/kernel/ms[^g]*{,/**} wklx,\n"
222 " deny /proc/sys/kernel/msg*/** wklx,\n"
223 " deny /proc/sys/kernel/s[^he]*{,/**} wklx,\n"
224 " deny /proc/sys/kernel/se[^m]*{,/**} wklx,\n"
225 " deny /proc/sys/kernel/sem*/** wklx,\n"
226 " deny /proc/sys/kernel/sh[^m]*{,/**} wklx,\n"
227 " deny /proc/sys/kernel/shm*/** wklx,\n"
228 " deny /proc/sys/kernel?*{,/**} wklx,\n"
229 " deny /proc/sys/n[^e]*{,/**} wklx,\n"
230 " deny /proc/sys/ne[^t]*{,/**} wklx,\n"
231 " deny /proc/sys/net?*{,/**} wklx,\n"
232 " deny /sys/[^fdck]*{,/**} wklx,\n"
233 " deny /sys/c[^l]*{,/**} wklx,\n"
234 " deny /sys/cl[^a]*{,/**} wklx,\n"
235 " deny /sys/cla[^s]*{,/**} wklx,\n"
236 " deny /sys/clas[^s]*{,/**} wklx,\n"
237 " deny /sys/class/[^n]*{,/**} wklx,\n"
238 " deny /sys/class/n[^e]*{,/**} wklx,\n"
239 " deny /sys/class/ne[^t]*{,/**} wklx,\n"
240 " deny /sys/class/net?*{,/**} wklx,\n"
241 " deny /sys/class?*{,/**} wklx,\n"
242 " deny /sys/d[^e]*{,/**} wklx,\n"
243 " deny /sys/de[^v]*{,/**} wklx,\n"
244 " deny /sys/dev[^i]*{,/**} wklx,\n"
245 " deny /sys/devi[^c]*{,/**} wklx,\n"
246 " deny /sys/devic[^e]*{,/**} wklx,\n"
247 " deny /sys/device[^s]*{,/**} wklx,\n"
248 " deny /sys/devices/[^v]*{,/**} wklx,\n"
249 " deny /sys/devices/v[^i]*{,/**} wklx,\n"
250 " deny /sys/devices/vi[^r]*{,/**} wklx,\n"
251 " deny /sys/devices/vir[^t]*{,/**} wklx,\n"
252 " deny /sys/devices/virt[^u]*{,/**} wklx,\n"
253 " deny /sys/devices/virtu[^a]*{,/**} wklx,\n"
254 " deny /sys/devices/virtua[^l]*{,/**} wklx,\n"
255 " deny /sys/devices/virtual/[^n]*{,/**} wklx,\n"
256 " deny /sys/devices/virtual/n[^e]*{,/**} wklx,\n"
257 " deny /sys/devices/virtual/ne[^t]*{,/**} wklx,\n"
258 " deny /sys/devices/virtual/net?*{,/**} wklx,\n"
259 " deny /sys/devices/virtual?*{,/**} wklx,\n"
260 " deny /sys/devices?*{,/**} wklx,\n"
261 " deny /sys/f[^s]*{,/**} wklx,\n"
262 " deny /sys/fs/[^c]*{,/**} wklx,\n"
263 " deny /sys/fs/c[^g]*{,/**} wklx,\n"
264 " deny /sys/fs/cg[^r]*{,/**} wklx,\n"
265 " deny /sys/fs/cgr[^o]*{,/**} wklx,\n"
266 " deny /sys/fs/cgro[^u]*{,/**} wklx,\n"
267 " deny /sys/fs/cgrou[^p]*{,/**} wklx,\n"
268 " deny /sys/fs/cgroup?*{,/**} wklx,\n"
269 " deny /sys/fs?*{,/**} wklx,\n"
270 ;
271
272 static const char AA_PROFILE_UNIX_SOCKETS[] =
273 "\n"
274 " ### Feature: unix\n"
275 " # Allow receive via unix sockets from anywhere\n"
276 " unix (receive),\n"
277 "\n"
278 " # Allow all unix sockets in the container\n"
279 " unix peer=(label=@{profile_name}),\n"
280 ;
281
282 static const char AA_PROFILE_CGROUP_NAMESPACES[] =
283 "\n"
284 " ### Feature: cgroup namespace\n"
285 " mount fstype=cgroup -> /sys/fs/cgroup/**,\n"
286 " mount fstype=cgroup2 -> /sys/fs/cgroup/**,\n"
287 ;
288
289 /* '_BASE' because we still need to append generated change_profile rules */
290 static const char AA_PROFILE_STACKING_BASE[] =
291 "\n"
292 " ### Feature: apparmor stacking\n"
293 " ### Configuration: apparmor profile loading (in namespace)\n"
294 " deny /sys/k[^e]*{,/**} wklx,\n"
295 " deny /sys/ke[^r]*{,/**} wklx,\n"
296 " deny /sys/ker[^n]*{,/**} wklx,\n"
297 " deny /sys/kern[^e]*{,/**} wklx,\n"
298 " deny /sys/kerne[^l]*{,/**} wklx,\n"
299 " deny /sys/kernel/[^s]*{,/**} wklx,\n"
300 " deny /sys/kernel/s[^e]*{,/**} wklx,\n"
301 " deny /sys/kernel/se[^c]*{,/**} wklx,\n"
302 " deny /sys/kernel/sec[^u]*{,/**} wklx,\n"
303 " deny /sys/kernel/secu[^r]*{,/**} wklx,\n"
304 " deny /sys/kernel/secur[^i]*{,/**} wklx,\n"
305 " deny /sys/kernel/securi[^t]*{,/**} wklx,\n"
306 " deny /sys/kernel/securit[^y]*{,/**} wklx,\n"
307 " deny /sys/kernel/security/[^a]*{,/**} wklx,\n"
308 " deny /sys/kernel/security/a[^p]*{,/**} wklx,\n"
309 " deny /sys/kernel/security/ap[^p]*{,/**} wklx,\n"
310 " deny /sys/kernel/security/app[^a]*{,/**} wklx,\n"
311 " deny /sys/kernel/security/appa[^r]*{,/**} wklx,\n"
312 " deny /sys/kernel/security/appar[^m]*{,/**} wklx,\n"
313 " deny /sys/kernel/security/apparm[^o]*{,/**} wklx,\n"
314 " deny /sys/kernel/security/apparmo[^r]*{,/**} wklx,\n"
315 " deny /sys/kernel/security/apparmor?*{,/**} wklx,\n"
316 " deny /sys/kernel/security?*{,/**} wklx,\n"
317 " deny /sys/kernel?*{,/**} wklx,\n"
318 ;
319
320 static const char AA_PROFILE_NO_STACKING[] =
321 "\n"
322 " ### Feature: apparmor stacking (not present)\n"
323 " deny /sys/k*{,/**} rwklx,\n"
324 ;
325
326 /* '_BASE' because we need to append change_profile for stacking */
327 static const char AA_PROFILE_NESTING_BASE[] =
328 "\n"
329 " ### Configuration: nesting\n"
330 " pivot_root,\n"
331 " ptrace,\n"
332 " signal,\n"
333 "\n"
334 /* NOTE: See conf.c's "nesting_helpers" for details. */
335 " deny /dev/.lxc/proc/** rw,\n"
336 " deny /dev/.lxc/sys/** rw,\n"
337 "\n"
338 " mount fstype=proc -> /usr/lib/*/lxc/**,\n"
339 " mount fstype=sysfs -> /usr/lib/*/lxc/**,\n"
340 "\n"
341 " # Allow nested LXD\n"
342 " mount none -> /var/lib/lxd/shmounts/,\n"
343 " mount /var/lib/lxd/shmounts/ -> /var/lib/lxd/shmounts/,\n"
344 " mount options=bind /var/lib/lxd/shmounts/** -> /var/lib/lxd/**,\n"
345 "\n"
346 " # FIXME: There doesn't seem to be a way to ask for:\n"
347 " # mount options=(ro,nosuid,nodev,noexec,remount,bind),\n"
348 " # as we always get mount to $cdir/proc/sys with those flags denied\n"
349 " # So allow all mounts until that is straightened out:\n"
350 " mount,\n"
351 ;
352
353 static const char AA_PROFILE_UNPRIVILEGED[] =
354 "\n"
355 " ### Configuration: unprivileged container\n"
356 " pivot_root,\n"
357 "\n"
358 " # Allow modifying mount propagation\n"
359 " mount options=(rw,make-slave) -> **,\n"
360 " mount options=(rw,make-rslave) -> **,\n"
361 " mount options=(rw,make-shared) -> **,\n"
362 " mount options=(rw,make-rshared) -> **,\n"
363 " mount options=(rw,make-private) -> **,\n"
364 " mount options=(rw,make-rprivate) -> **,\n"
365 " mount options=(rw,make-unbindable) -> **,\n"
366 " mount options=(rw,make-runbindable) -> **,\n"
367 "\n"
368 " # Allow all bind-mounts\n"
369 " mount options=(rw,bind),\n"
370 " mount options=(rw,rbind),\n"
371 "\n"
372 " # Allow remounting things read-only\n"
373 " mount options=(ro,remount),\n"
374 ;
375
376 static bool check_mount_feature_enabled(void)
377 {
378 return mount_features_enabled == 1;
379 }
380
381 static void load_mount_features_enabled(void)
382 {
383 struct stat statbuf;
384 int ret;
385
386 ret = stat(AA_MOUNT_RESTR, &statbuf);
387 if (ret == 0)
388 mount_features_enabled = 1;
389 }
390
391 /* aa_getcon is not working right now. Use our hand-rolled version below */
392 static int apparmor_enabled(void)
393 {
394 FILE *fin;
395 char e;
396 int ret;
397
398 fin = fopen_cloexec(AA_ENABLED_FILE, "r");
399 if (!fin)
400 return 0;
401 ret = fscanf(fin, "%c", &e);
402 fclose(fin);
403 if (ret == 1 && e == 'Y') {
404 load_mount_features_enabled();
405 return 1;
406 }
407
408 return 0;
409 }
410
411 static char *apparmor_process_label_get(pid_t pid)
412 {
413 char path[100], *space;
414 int ret;
415 char *buf = NULL, *newbuf;
416 int sz = 0;
417 FILE *f;
418
419 ret = snprintf(path, 100, "/proc/%d/attr/current", pid);
420 if (ret < 0 || ret >= 100) {
421 ERROR("path name too long");
422 return NULL;
423 }
424 again:
425 f = fopen_cloexec(path, "r");
426 if (!f) {
427 SYSERROR("opening %s", path);
428 free(buf);
429 return NULL;
430 }
431 sz += 1024;
432 newbuf = realloc(buf, sz);
433 if (!newbuf) {
434 free(buf);
435 ERROR("out of memory");
436 fclose(f);
437 return NULL;
438 }
439 buf = newbuf;
440 memset(buf, 0, sz);
441 ret = fread(buf, 1, sz - 1, f);
442 fclose(f);
443 if (ret < 0) {
444 ERROR("reading %s", path);
445 free(buf);
446 return NULL;
447 }
448 if (ret >= sz)
449 goto again;
450 space = strchr(buf, '\n');
451 if (space)
452 *space = '\0';
453 space = strchr(buf, ' ');
454 if (space)
455 *space = '\0';
456 return buf;
457 }
458
459 /*
460 * Probably makes sense to reorganize these to only read
461 * the label once
462 */
463 static bool apparmor_am_unconfined(void)
464 {
465 char *p = apparmor_process_label_get(lxc_raw_getpid());
466 bool ret = false;
467 if (!p || strcmp(p, "unconfined") == 0)
468 ret = true;
469 free(p);
470 return ret;
471 }
472
473 static bool aa_needs_transition(char *curlabel)
474 {
475 if (!curlabel)
476 return false;
477 if (strcmp(curlabel, "unconfined") == 0)
478 return false;
479 if (strcmp(curlabel, "/usr/bin/lxc-start") == 0)
480 return false;
481 return true;
482 }
483
484 static inline void uint64hex(char *buf, uint64_t num)
485 {
486 size_t i;
487
488 buf[16] = 0;
489 for (i = 16; i--;) {
490 char c = (char)(num & 0xf);
491 buf[i] = c + (c < 0xa ? '0' : 'a' - 0xa);
492 num >>= 4;
493 }
494 }
495
496 static inline char *shorten_apparmor_name(char *name)
497 {
498 size_t len = strlen(name);
499 if (len + 7 > 253) {
500 uint64_t hash;
501 hash = fnv_64a_buf(name, len, FNV1A_64_INIT);
502 name = must_realloc(name, 16 + 1);
503 uint64hex(name, hash);
504 }
505
506 return name;
507 }
508
509 /* Replace slashes with hyphens */
510 static inline void sanitize_path(char *path)
511 {
512 size_t i;
513
514 for (i = 0; path[i]; i++)
515 if (path[i] == '/')
516 path[i] = '-';
517 }
518
519 static inline char *apparmor_dir(const char *ctname, const char *lxcpath)
520 {
521 return must_make_path(lxcpath, ctname, "apparmor", NULL);
522 }
523
524
525 static inline char *apparmor_profile_full(const char *ctname, const char *lxcpath)
526 {
527 return shorten_apparmor_name(must_concat(NULL, "lxc-", ctname, "_<", lxcpath, ">", NULL));
528 }
529
530 /* Like apparmor_profile_full() but with slashes replaced by hyphens */
531 static inline char *apparmor_namespace(const char *ctname, const char *lxcpath)
532 {
533 char *full;
534
535 full = apparmor_profile_full(ctname, lxcpath);
536 sanitize_path(full);
537
538 return full;
539 }
540
541 /* FIXME: This is currently run only in the context of a constructor (via the
542 * initial lsm_init() called due to its __attribute__((constructor)), so we
543 * do not have ERROR/... macros available, so there are some fprintf(stderr)s
544 * in there.
545 */
546 static bool check_apparmor_parser_version()
547 {
548 struct lxc_popen_FILE *parserpipe;
549 int rc;
550 int major = 0, minor = 0, micro = 0;
551
552 parserpipe = lxc_popen("apparmor_parser --version");
553 if (!parserpipe) {
554 fprintf(stderr, "Failed to run check for apparmor_parser\n");
555 return false;
556 }
557
558 rc = fscanf(parserpipe->f, "AppArmor parser version %d.%d.%d", &major, &minor, &micro);
559 if (rc < 1) {
560 lxc_pclose(parserpipe);
561 /* We stay silent for now as this most likely means the shell
562 * lxc_popen executed failed to find the apparmor_parser binary.
563 * See the FIXME comment above for details.
564 */
565 return false;
566 }
567
568 rc = lxc_pclose(parserpipe);
569 if (rc < 0) {
570 fprintf(stderr, "Error waiting for child process\n");
571 return false;
572 }
573 if (rc != 0) {
574 fprintf(stderr, "'apparmor_parser --version' executed with an error status\n");
575 return false;
576 }
577
578 aa_supports_unix = (major > 2) ||
579 (major == 2 && minor > 10) ||
580 (major == 2 && minor == 10 && micro >= 95);
581
582 return true;
583 }
584
585 static bool file_is_yes(const char *path)
586 {
587 ssize_t rd;
588 int fd;
589 char buf[8]; /* we actually just expect "yes" or "no" */
590
591 fd = open(path, O_RDONLY | O_CLOEXEC);
592 if (fd < 0)
593 return false;
594
595 rd = lxc_read_nointr(fd, buf, sizeof(buf));
596 close(fd);
597
598 return rd >= 4 && strncmp(buf, "yes\n", 4) == 0;
599 }
600
601 static bool apparmor_can_stack()
602 {
603 int major, minor, scanned;
604 FILE *f;
605
606 if (!file_is_yes("/sys/kernel/security/apparmor/features/domain/stack"))
607 return false;
608
609 f = fopen_cloexec("/sys/kernel/security/apparmor/features/domain/version", "r");
610 if (!f)
611 return false;
612
613 scanned = fscanf(f, "%d.%d", &major, &minor);
614 fclose(f);
615 if (scanned != 2)
616 return false;
617
618 return major > 1 || (major == 1 && minor >= 2);
619 }
620
621 static void must_append_sized_full(char **buf, size_t *bufsz, const char *data,
622 size_t size, bool append_newline)
623 {
624 size_t newsize = *bufsz + size;
625
626 if (append_newline)
627 ++newsize;
628
629 *buf = must_realloc(*buf, newsize);
630 memcpy(*buf + *bufsz, data, size);
631
632 if (append_newline)
633 (*buf)[newsize - 1] = '\n';
634
635 *bufsz = newsize;
636 }
637
638 static void must_append_sized(char **buf, size_t *bufsz, const char *data, size_t size)
639 {
640 return must_append_sized_full(buf, bufsz, data, size, false);
641 }
642
643 static bool is_privileged(struct lxc_conf *conf)
644 {
645 return lxc_list_empty(&conf->id_map);
646 }
647
648 static const char* AA_ALL_DEST_PATH_LIST[] = {
649 " -> /[^spd]*{,/**},\n",
650 " -> /d[^e]*{,/**},\n",
651 " -> /de[^v]*{,/**},\n",
652 " -> /dev/.[^l]*{,/**},\n",
653 " -> /dev/.l[^x]*{,/**},\n",
654 " -> /dev/.lx[^c]*{,/**},\n",
655 " -> /dev/.lxc?*{,/**},\n",
656 " -> /dev/[^.]*{,/**},\n",
657 " -> /dev?*{,/**},\n",
658 " -> /p[^r]*{,/**},\n",
659 " -> /pr[^o]*{,/**},\n",
660 " -> /pro[^c]*{,/**},\n",
661 " -> /proc?*{,/**},\n",
662 " -> /s[^y]*{,/**},\n",
663 " -> /sy[^s]*{,/**},\n",
664 " -> /sys?*{,/**},\n",
665 NULL,
666 };
667
668 static const struct mntopt_t {
669 const char *opt;
670 size_t len;
671 } REMOUNT_OPTIONS[] = {
672 { ",nodev", sizeof(",nodev")-1 },
673 { ",nosuid", sizeof(",nosuid")-1 },
674 { ",noexec", sizeof(",noexec")-1 },
675 };
676
677 static void append_remount_rule(char **profile, size_t *size, const char *rule)
678 {
679 size_t rule_len = strlen(rule);
680
681 for (const char **dest = AA_ALL_DEST_PATH_LIST; *dest; ++dest) {
682 must_append_sized(profile, size, rule, rule_len);
683 must_append_sized(profile, size, *dest, strlen(*dest));
684 }
685 }
686
687 static void append_all_remount_rules(char **profile, size_t *size)
688 {
689 /*
690 * That's 30, and we add at most:
691 * ",nodev,nosuid,noexec,strictatime -> /dev/.lx[^c]*{,/ **},\ n",
692 * which is anouther ~58, this s hould be enough:
693 */
694 char buf[128] = " mount options=(ro,remount,bind";
695 const size_t buf_append_pos = strlen(buf);
696
697 const size_t opt_count = ARRAY_SIZE(REMOUNT_OPTIONS);
698 size_t opt_bits;
699
700 must_append_sized(profile, size,
701 "# allow various ro-bind-*re*mounts\n",
702 sizeof("# allow various ro-bind-*re*mounts\n")-1);
703
704 for (opt_bits = 0; opt_bits != 1 << opt_count; ++opt_bits) {
705 size_t at = buf_append_pos;
706 unsigned bit = 1;
707 size_t o;
708
709 for (o = 0; o != opt_count; ++o, bit <<= 1) {
710 if (opt_bits & bit) {
711 const struct mntopt_t *opt = &REMOUNT_OPTIONS[o];
712 memcpy(&buf[at], opt->opt, opt->len);
713 at += opt->len;
714 }
715 }
716
717 memcpy(&buf[at], ")", sizeof(")"));
718 append_remount_rule(profile, size, buf);
719
720 /* noatime and strictatime don't go together */
721 memcpy(&buf[at], ",noatime)", sizeof(",noatime)"));
722 append_remount_rule(profile, size, buf);
723 memcpy(&buf[at], ",strictatime)", sizeof(",strictatime)"));
724 append_remount_rule(profile, size, buf);
725 }
726 }
727
728 static char *get_apparmor_profile_content(struct lxc_conf *conf, const char *lxcpath)
729 {
730 char *profile, *profile_name_full;
731 size_t size;
732 struct lxc_list *it;
733
734 profile_name_full = apparmor_profile_full(conf->name, lxcpath);
735
736 profile = must_concat(NULL,
737 "#include <tunables/global>\n"
738 "profile \"", profile_name_full, "\" flags=(attach_disconnected,mediate_deleted) {\n",
739 NULL);
740 size = strlen(profile);
741
742 must_append_sized(&profile, &size, AA_PROFILE_BASE,
743 STRARRAYLEN(AA_PROFILE_BASE));
744
745 append_all_remount_rules(&profile, &size);
746
747 if (aa_supports_unix)
748 must_append_sized(&profile, &size, AA_PROFILE_UNIX_SOCKETS,
749 STRARRAYLEN(AA_PROFILE_UNIX_SOCKETS));
750
751 if (file_exists("/proc/self/ns/cgroup"))
752 must_append_sized(&profile, &size, AA_PROFILE_CGROUP_NAMESPACES,
753 STRARRAYLEN(AA_PROFILE_CGROUP_NAMESPACES));
754
755 if (aa_can_stack && !aa_is_stacked) {
756 char *namespace, *temp;
757
758 must_append_sized(&profile, &size, AA_PROFILE_STACKING_BASE,
759 STRARRAYLEN(AA_PROFILE_STACKING_BASE));
760
761 namespace = apparmor_namespace(conf->name, lxcpath);
762 temp = must_concat(NULL, " change_profile -> \":", namespace, ":*\",\n"
763 " change_profile -> \":", namespace, "://*\",\n",
764 NULL);
765 free(namespace);
766
767 must_append_sized(&profile, &size, temp, strlen(temp));
768 free(temp);
769 } else {
770 must_append_sized(&profile, &size, AA_PROFILE_NO_STACKING,
771 STRARRAYLEN(AA_PROFILE_NO_STACKING));
772 }
773
774 if (conf->lsm_aa_allow_nesting) {
775 must_append_sized(&profile, &size, AA_PROFILE_NESTING_BASE,
776 STRARRAYLEN(AA_PROFILE_NESTING_BASE));
777
778 if (!aa_can_stack || aa_is_stacked) {
779 char *temp;
780
781 temp = must_concat(NULL, " change_profile -> \"",
782 profile_name_full, "\",\n", NULL);
783 must_append_sized(&profile, &size, temp, strlen(temp));
784 free(temp);
785 }
786 }
787
788 if (!is_privileged(conf) || am_host_unpriv())
789 must_append_sized(&profile, &size, AA_PROFILE_UNPRIVILEGED,
790 STRARRAYLEN(AA_PROFILE_UNPRIVILEGED));
791
792 lxc_list_for_each(it, &conf->lsm_aa_raw) {
793 const char *line = it->elem;
794
795 must_append_sized_full(&profile, &size, line, strlen(line), true);
796 }
797
798 /* include terminating \0 byte */
799 must_append_sized(&profile, &size, "}\n", 3);
800
801 free(profile_name_full);
802
803 return profile;
804 }
805
806 /*
807 * apparmor_parser creates a cache file using the parsed file's name as a name.
808 * This means there may be multiple containers with the same name but different
809 * lxcpaths. Therefore we need a sanitized version of the complete profile name
810 * as profile file-name.
811 * We already get this exactly from apparmor_namespace().
812 */
813 static char *make_apparmor_profile_path(const char *ctname, const char *lxcpath)
814 {
815 char *ret, *filename;
816
817 filename = apparmor_namespace(ctname, lxcpath);
818 ret = must_make_path(lxcpath, ctname, "apparmor", filename, NULL);
819 free(filename);
820
821 return ret;
822 }
823
824 static char *make_apparmor_namespace_path(const char *ctname, const char *lxcpath)
825 {
826 char *ret, *namespace;
827
828 namespace = apparmor_namespace(ctname, lxcpath);
829 ret = must_make_path("/sys/kernel/security/apparmor/policy/namespaces", namespace, NULL);
830 free(namespace);
831
832 return ret;
833 }
834
835 static bool make_apparmor_namespace(struct lxc_conf *conf, const char *lxcpath)
836 {
837 char *path;
838
839 if (!aa_can_stack || aa_is_stacked)
840 return true;
841
842 path = make_apparmor_namespace_path(conf->name, lxcpath);
843 errno = 0;
844 if (mkdir(path, 0755) < 0 && errno != EEXIST) {
845 SYSERROR("Error creating AppArmor namespace: %s", path);
846 free(path);
847 return false;
848 }
849 free(path);
850
851 return true;
852 }
853
854 static void remove_apparmor_namespace(struct lxc_conf *conf, const char *lxcpath)
855 {
856 char *path;
857
858 path = make_apparmor_namespace_path(conf->name, lxcpath);
859 if (rmdir(path) != 0)
860 SYSERROR("Error removing AppArmor namespace");
861 free(path);
862 }
863
864 struct apparmor_parser_args {
865 char cmd;
866 char *file;
867 };
868
869 static int apparmor_parser_exec(void *data)
870 {
871 struct apparmor_parser_args *args = data;
872 char cmdbuf[] = { '-', args->cmd, 'W', 'L', 0 };
873
874 execlp("apparmor_parser", "apparmor_parser", cmdbuf, APPARMOR_CACHE_DIR, args->file, NULL);
875
876 return -1;
877 }
878
879 static int run_apparmor_parser(char command,
880 struct lxc_conf *conf,
881 const char *lxcpath)
882 {
883 char output[PATH_MAX];
884 int ret;
885 struct apparmor_parser_args args = {
886 .cmd = command,
887 .file = make_apparmor_profile_path(conf->name, lxcpath),
888 };
889
890 ret = run_command(output, sizeof(output), apparmor_parser_exec, (void*)&args);
891 if (ret < 0) {
892 ERROR("Failed to run apparmor_parser on \"%s\": %s", args.file, output);
893 ret = -1;
894 }
895
896
897 free(args.file);
898 return ret;
899 }
900
901 static void remove_apparmor_profile(struct lxc_conf *conf, const char *lxcpath)
902 {
903 char *path;
904
905 /* It's ok if these deletes fail: if the container was never started,
906 * we'll have never written a profile or cached it.
907 */
908
909 path = make_apparmor_profile_path(conf->name, lxcpath);
910 (void)unlink(path);
911 free(path);
912
913 /* Also remove the apparmor/ subdirectory */
914 path = apparmor_dir(conf->name, lxcpath);
915 (void)rmdir(path);
916 free(path);
917 }
918
919 static int load_apparmor_profile(struct lxc_conf *conf, const char *lxcpath)
920 {
921 struct stat profile_sb;
922 size_t content_len;
923 int ret = -1;
924 size_t old_len = 0;
925 char *profile_path = NULL, *old_content = NULL, *new_content = NULL;
926 int profile_fd = -1;
927
928 if (!make_apparmor_namespace(conf, lxcpath))
929 return -1;
930
931 /* In order to avoid forcing a profile parse (potentially slow) on
932 * every container start, let's use apparmor's binary policy cache,
933 * which checks mtime of the files to figure out if the policy needs to
934 * be regenerated.
935 *
936 * Since it uses mtimes, we shouldn't just always write out our local
937 * apparmor template; instead we should check to see whether the
938 * template is the same as ours. If it isn't we should write our
939 * version out so that the new changes are reflected and we definitely
940 * force a recompile.
941 */
942
943 profile_path = make_apparmor_profile_path(conf->name, lxcpath);
944 profile_fd = open(profile_path, O_RDONLY | O_CLOEXEC);
945 if (profile_fd >= 0) {
946 if (fstat(profile_fd, &profile_sb) < 0) {
947 SYSERROR("Error accessing old profile from %s",
948 profile_path);
949 goto out;
950 }
951 old_len = profile_sb.st_size;
952 old_content = lxc_strmmap(NULL, old_len, PROT_READ,
953 MAP_PRIVATE, profile_fd, 0);
954 if (!old_content) {
955 SYSERROR("Failed to mmap old profile from %s",
956 profile_path);
957 goto out;
958 }
959 } else if (errno != ENOENT) {
960 SYSERROR("Error reading old profile from %s", profile_path);
961 goto out;
962 }
963
964 new_content = get_apparmor_profile_content(conf, lxcpath);
965 if (!new_content)
966 goto out;
967
968 content_len = strlen(new_content);
969
970 if (!old_content || old_len != content_len || memcmp(old_content, new_content, content_len) != 0) {
971 char *path;
972
973 ret = mkdir_p(APPARMOR_CACHE_DIR, 0755);
974 if (ret < 0) {
975 SYSERROR("Error creating AppArmor profile cache directory " APPARMOR_CACHE_DIR);
976 goto out;
977 }
978
979 path = apparmor_dir(conf->name, lxcpath);
980 ret = mkdir_p(path, 0755);
981 if (ret < 0) {
982 SYSERROR("Error creating AppArmor profile directory: %s", path);
983 free(path);
984 goto out;
985 }
986 free(path);
987
988 ret = lxc_write_to_file(profile_path, new_content, content_len, false, 0600);
989 if (ret < 0) {
990 SYSERROR("Error writing profile to %s", profile_path);
991 goto out;
992 }
993 }
994
995 ret = run_apparmor_parser(AA_CMD_LOAD, conf, lxcpath);
996 if (ret != 0)
997 goto out_remove_profile;
998
999 conf->lsm_aa_profile_created = true;
1000
1001 goto out_ok;
1002
1003 out_remove_profile:
1004 remove_apparmor_profile(conf, lxcpath);
1005 out:
1006 remove_apparmor_namespace(conf, lxcpath);
1007 out_ok:
1008 if (profile_fd >= 0) {
1009 if (old_content)
1010 lxc_strmunmap(old_content, old_len);
1011 close(profile_fd);
1012 }
1013 free(profile_path);
1014 free(new_content);
1015 return ret;
1016 }
1017
1018 /*
1019 * Ensure that the container's policy namespace is unloaded to free kernel
1020 * memory. This does not delete the policy from disk or cache.
1021 */
1022 static void apparmor_cleanup(struct lxc_conf *conf, const char *lxcpath)
1023 {
1024 if (!aa_admin)
1025 return;
1026
1027 if (!conf->lsm_aa_profile_created)
1028 return;
1029
1030 remove_apparmor_namespace(conf, lxcpath);
1031 (void)run_apparmor_parser(AA_CMD_UNLOAD, conf, lxcpath);
1032
1033 remove_apparmor_profile(conf, lxcpath);
1034 }
1035
1036 static int apparmor_prepare(struct lxc_conf *conf, const char *lxcpath)
1037 {
1038 int ret = -1;
1039 const char *label;
1040 char *curlabel = NULL, *genlabel = NULL;
1041
1042 if (!aa_enabled) {
1043 ERROR("AppArmor not enabled");
1044 return -1;
1045 }
1046
1047 label = conf->lsm_aa_profile;
1048
1049 /* user may request that we just ignore apparmor */
1050 if (label && strcmp(label, AA_UNCHANGED) == 0) {
1051 INFO("AppArmor profile unchanged per user request");
1052 conf->lsm_aa_profile_computed = must_copy_string(label);
1053 return 0;
1054 }
1055
1056 if (label && strcmp(label, AA_GENERATED) == 0) {
1057 if (!aa_parser_available) {
1058 ERROR("Cannot use generated profile: apparmor_parser not available");
1059 goto out;
1060 }
1061
1062 /* auto-generate profile based on available/requested security features */
1063 if (load_apparmor_profile(conf, lxcpath) != 0) {
1064 ERROR("Failed to load generated AppArmor profile");
1065 goto out;
1066 }
1067
1068 genlabel = apparmor_profile_full(conf->name, lxcpath);
1069 if (!genlabel) {
1070 ERROR("Failed to build AppArmor profile name");
1071 goto out;
1072 }
1073
1074 if (aa_can_stack && !aa_is_stacked) {
1075 char *namespace = apparmor_namespace(conf->name, lxcpath);
1076 size_t llen = strlen(genlabel);
1077 must_append_sized(&genlabel, &llen, "//&:", STRARRAYLEN("//&:"));
1078 must_append_sized(&genlabel, &llen, namespace, strlen(namespace));
1079 must_append_sized(&genlabel, &llen, ":", STRARRAYLEN(":") + 1); /* with the nul byte */
1080 free(namespace);
1081 }
1082
1083 label = genlabel;
1084 }
1085
1086 curlabel = apparmor_process_label_get(lxc_raw_getpid());
1087
1088 if (!aa_can_stack && aa_needs_transition(curlabel)) {
1089 /* we're already confined, and stacking isn't supported */
1090
1091 if (!label || strcmp(curlabel, label) == 0) {
1092 /* no change requested */
1093 ret = 0;
1094 goto out;
1095 }
1096
1097 ERROR("Already AppArmor confined, but new label requested.");
1098 goto out;
1099 }
1100
1101 if (!label) {
1102 if (cgns_supported())
1103 label = AA_DEF_PROFILE_CGNS;
1104 else
1105 label = AA_DEF_PROFILE;
1106 }
1107
1108 if (!check_mount_feature_enabled() && strcmp(label, "unconfined") != 0) {
1109 WARN("Incomplete AppArmor support in your kernel");
1110 if (!conf->lsm_aa_allow_incomplete) {
1111 ERROR("If you really want to start this container, set");
1112 ERROR("lxc.apparmor.allow_incomplete = 1");
1113 ERROR("in your container configuration file");
1114 goto out;
1115 }
1116 }
1117
1118 conf->lsm_aa_profile_computed = must_copy_string(label);
1119 ret = 0;
1120
1121 out:
1122 if (genlabel) {
1123 free(genlabel);
1124 if (ret != 0)
1125 apparmor_cleanup(conf, lxcpath);
1126 }
1127 free(curlabel);
1128 return ret;
1129 }
1130
1131 /*
1132 * apparmor_process_label_set: Set AppArmor process profile
1133 *
1134 * @label : the profile to set
1135 * @conf : the container configuration to use if @label is NULL
1136 * @default : use the default profile if @label is NULL
1137 * @on_exec : this is ignored. Apparmor profile will be changed immediately
1138 *
1139 * Returns 0 on success, < 0 on failure
1140 *
1141 * Notes: This relies on /proc being available.
1142 */
1143 static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf,
1144 bool on_exec)
1145 {
1146 int label_fd, ret;
1147 pid_t tid;
1148 const char *label;
1149
1150 if (!aa_enabled) {
1151 ERROR("AppArmor not enabled");
1152 return -1;
1153 }
1154
1155 label = inlabel ? inlabel : conf->lsm_aa_profile_computed;
1156 if (!label) {
1157 ERROR("LSM wasn't prepared");
1158 return -1;
1159 }
1160
1161 /* user may request that we just ignore apparmor */
1162 if (strcmp(label, AA_UNCHANGED) == 0) {
1163 INFO("AppArmor profile unchanged per user request");
1164 return 0;
1165 }
1166
1167 if (strcmp(label, "unconfined") == 0 && apparmor_am_unconfined()) {
1168 INFO("AppArmor profile unchanged");
1169 return 0;
1170 }
1171 tid = lxc_raw_gettid();
1172 label_fd = lsm_process_label_fd_get(tid, on_exec);
1173 if (label_fd < 0) {
1174 SYSERROR("Failed to change AppArmor profile to %s", label);
1175 return -1;
1176 }
1177
1178 ret = lsm_process_label_set_at(label_fd, label, on_exec);
1179 close(label_fd);
1180 if (ret < 0) {
1181 ERROR("Failed to change AppArmor profile to %s", label);
1182 return -1;
1183 }
1184
1185 INFO("Changed AppArmor profile to %s", label);
1186 return 0;
1187 }
1188
1189 static struct lsm_drv apparmor_drv = {
1190 .name = "AppArmor",
1191 .enabled = apparmor_enabled,
1192 .process_label_get = apparmor_process_label_get,
1193 .process_label_set = apparmor_process_label_set,
1194 .prepare = apparmor_prepare,
1195 .cleanup = apparmor_cleanup,
1196 };
1197
1198 struct lsm_drv *lsm_apparmor_drv_init(void)
1199 {
1200 bool have_mac_admin = false;
1201
1202 if (!apparmor_enabled())
1203 return NULL;
1204
1205 /* We only support generated profiles when apparmor_parser is usable */
1206 if (!check_apparmor_parser_version())
1207 goto out;
1208
1209 aa_parser_available = true;
1210
1211 aa_can_stack = apparmor_can_stack();
1212 if (aa_can_stack)
1213 aa_is_stacked = file_is_yes("/sys/kernel/security/apparmor/.ns_stacked");
1214
1215 #if HAVE_LIBCAP
1216 have_mac_admin = lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE);
1217 #endif
1218
1219 if (!have_mac_admin)
1220 WARN("Per-container AppArmor profiles are disabled because the mac_admin capability is missing");
1221 else if (am_host_unpriv() && !aa_is_stacked)
1222 WARN("Per-container AppArmor profiles are disabled because LXC is running in an unprivileged container without stacking");
1223 else
1224 aa_admin = true;
1225
1226 out:
1227 aa_enabled = 1;
1228 return &apparmor_drv;
1229 }