]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/apparmor.c
licensing: Add missing headers and FSF address
[mirror_lxc.git] / src / lxc / apparmor.c
CommitLineData
250b1eec
SG
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
e075f5d9 21#include <stdio.h>
9958532b 22#include <stdlib.h>
e075f5d9
SH
23#include <unistd.h>
24#include <errno.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/mount.h>
28
29#include "log.h"
d80cfe71 30#include "apparmor.h"
e075f5d9
SH
31
32lxc_log_define(lxc_apparmor, lxc);
33
34#if HAVE_APPARMOR
e075f5d9
SH
35#include <sys/apparmor.h>
36
37#define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask"
38#define AA_ENABLED_FILE "/sys/module/apparmor/parameters/enabled"
39
9958532b
SH
40
41/* caller must free the returned profile */
42extern char *aa_get_profile(pid_t pid)
e075f5d9 43{
9958532b 44 char path[100], *space;
e075f5d9 45 int ret;
9958532b
SH
46 char *buf = NULL;
47 int sz = 0;
48 FILE *f;
49
50 ret = snprintf(path, 100, "/proc/%d/attr/current", pid);
51 if (ret < 0 || ret >= 100) {
52 ERROR("path name too long");
53 return NULL;
54 }
55again:
56 f = fopen(path, "r");
57 if (!f) {
58 SYSERROR("opening %s\n", path);
00b6be44
SH
59 if (buf)
60 free(buf);
9958532b
SH
61 return NULL;
62 }
63 sz += 1024;
64 buf = realloc(buf, sz);
626ad11b 65 memset(buf, 0, sz);
9958532b
SH
66 if (!buf) {
67 ERROR("out of memory");
68 fclose(f);
69 return NULL;
70 }
626ad11b 71 ret = fread(buf, 1, sz - 1, f);
e075f5d9 72 fclose(f);
9958532b
SH
73 if (ret >= sz)
74 goto again;
75 if (ret < 0) {
76 ERROR("reading %s\n", path);
77 free(buf);
78 return NULL;
79 }
80 space = index(buf, ' ');
81 if (space)
82 *space = '\0';
83 return buf;
84}
85
86static int aa_am_unconfined(void)
87{
88 char *p = aa_get_profile(getpid());
89 int ret = 0;
90 if (!p || strcmp(p, "unconfined") == 0)
91 ret = 1;
92 if (p)
93 free(p);
94 return ret;
e075f5d9
SH
95}
96
97/* aa_getcon is not working right now. Use our hand-rolled version below */
98static int check_apparmor_enabled(void)
99{
100 struct stat statbuf;
101 FILE *fin;
102 char e;
103 int ret;
104
105 ret = stat(AA_MOUNT_RESTR, &statbuf);
106 if (ret != 0)
107 return 0;
108 fin = fopen(AA_ENABLED_FILE, "r");
109 if (!fin)
110 return 0;
111 ret = fscanf(fin, "%c", &e);
112 fclose(fin);
113 if (ret == 1 && e == 'Y')
114 return 1;
115 return 0;
116}
117
118extern void apparmor_handler_init(struct lxc_handler *handler)
119{
120 handler->aa_enabled = check_apparmor_enabled();
121 INFO("aa_enabled set to %d\n", handler->aa_enabled);
122}
123
124#define AA_DEF_PROFILE "lxc-container-default"
9958532b
SH
125
126extern int do_apparmor_load(int aa_enabled, char *aa_profile,
127 int umount_proc, int dropprivs)
e075f5d9 128{
9958532b 129 if (!aa_enabled) {
e075f5d9
SH
130 INFO("apparmor not enabled");
131 return 0;
132 }
133 INFO("setting up apparmor");
134
9958532b
SH
135 if (!aa_profile)
136 aa_profile = AA_DEF_PROFILE;
e075f5d9 137
9958532b 138 if (strcmp(aa_profile, "unconfined") == 0 && !dropprivs && aa_am_unconfined()) {
e075f5d9
SH
139 INFO("apparmor profile unchanged");
140 return 0;
141 }
142
9958532b
SH
143 //if (aa_change_onexec(aa_profile) < 0) {
144 if (aa_change_profile(aa_profile) < 0) {
145 SYSERROR("failed to change apparmor profile to %s", aa_profile);
e075f5d9
SH
146 return -1;
147 }
9958532b 148 if (umount_proc == 1)
e075f5d9
SH
149 umount("/proc");
150
9958532b 151 INFO("changed apparmor profile to %s", aa_profile);
e075f5d9
SH
152
153 return 0;
154}
155
9958532b
SH
156extern int apparmor_load(struct lxc_handler *handler)
157{
158 if (!handler->conf->aa_profile)
159 handler->conf->aa_profile = AA_DEF_PROFILE;
160 return do_apparmor_load(handler->aa_enabled,
161 handler->conf->aa_profile,
162 handler->conf->lsm_umount_proc, 0);
163}
164
165extern int attach_apparmor(char *profile)
166{
167 if (!profile)
168 return 0;
169 if (!check_apparmor_enabled())
170 return 0;
171 if (strcmp(profile, "unconfined") == 0)
172 return 0;
173 return do_apparmor_load(1, profile, 0, 1);
174}
175
e075f5d9
SH
176/*
177 * this will likely move to a generic lsm.c, as selinux and smack will both
178 * also want proc mounted in the container so as to transition
179 */
180extern int lsm_mount_proc_if_needed(char *root_src, char *rootfs_tgt)
181{
182 char path[MAXPATHLEN];
183 char link[20];
184 int linklen, ret;
185
186 ret = snprintf(path, MAXPATHLEN, "%s/proc/self", root_src ? rootfs_tgt : "");
187 if (ret < 0 || ret >= MAXPATHLEN) {
188 SYSERROR("proc path name too long");
189 return -1;
190 }
191 memset(link, 0, 20);
192 linklen = readlink(path, link, 20);
193 INFO("I am %d, /proc/self points to %s\n", getpid(), link);
194 ret = snprintf(path, MAXPATHLEN, "%s/proc", root_src ? rootfs_tgt : "");
195 if (linklen < 0) /* /proc not mounted */
196 goto domount;
197 /* can't be longer than rootfs/proc/1 */
198 if (strncmp(link, "1", linklen) != 0) {
199 /* wrong /procs mounted */
200 umount2(path, MNT_DETACH); /* ignore failure */
201 goto domount;
202 }
203 /* the right proc is already mounted */
204 return 0;
205
206domount:
207 if (mount("proc", path, "proc", 0, NULL))
208 return -1;
209 INFO("Mounted /proc for the container\n");
210 return 1;
211}
212#else
213extern void apparmor_handler_init(struct lxc_handler *handler) {
214 INFO("apparmor_load - apparmor is disabled");
215}
216#endif