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