]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxclock.c
Merge pull request #3059 from brauner/2019-06-21/seccomp_notify
[mirror_lxc.git] / src / lxc / lxclock.c
1 /* liblxcapi
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 #ifndef _GNU_SOURCE
22 #define _GNU_SOURCE 1
23 #endif
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <malloc.h>
27 #include <pthread.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/file.h>
31 #include <unistd.h>
32
33 #include <lxc/lxccontainer.h>
34
35 #include "config.h"
36 #include "log.h"
37 #include "lxclock.h"
38 #include "utils.h"
39
40 #ifdef MUTEX_DEBUGGING
41 #include <execinfo.h>
42 #endif
43
44 #define MAX_STACKDEPTH 25
45
46 lxc_log_define(lxclock, lxc);
47
48 #ifdef MUTEX_DEBUGGING
49 static pthread_mutex_t thread_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
50
51 static inline void dump_stacktrace(void)
52 {
53 void *array[MAX_STACKDEPTH];
54 size_t size;
55 char **strings;
56 size_t i;
57
58 size = backtrace(array, MAX_STACKDEPTH);
59 strings = backtrace_symbols(array, size);
60
61 /* Using fprintf here as our logging module is not thread safe. */
62 fprintf(stderr, "\tObtained %zu stack frames\n", size);
63
64 for (i = 0; i < size; i++)
65 fprintf(stderr, "\t\t%s\n", strings[i]);
66
67 free(strings);
68 }
69 #else
70 static pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER;
71
72 static inline void dump_stacktrace(void) {;}
73 #endif
74
75 static void lock_mutex(pthread_mutex_t *l)
76 {
77 int ret;
78
79 ret = pthread_mutex_lock(l);
80 if (ret != 0) {
81 SYSERROR("Failed to acquire mutex");
82 dump_stacktrace();
83 _exit(EXIT_FAILURE);
84 }
85 }
86
87 static void unlock_mutex(pthread_mutex_t *l)
88 {
89 int ret;
90
91 ret = pthread_mutex_unlock(l);
92 if (ret != 0) {
93 SYSERROR("Failed to release mutex");
94 dump_stacktrace();
95 _exit(EXIT_FAILURE);
96 }
97 }
98
99 static char *lxclock_name(const char *p, const char *n)
100 {
101 int ret;
102 size_t len;
103 char *dest, *rundir;
104
105 /* lockfile will be:
106 * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
107 * or
108 * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root
109 */
110
111 /* length of "/lxc/lock/" + $lxcpath + "/" + "." + $lxcname + '\0' */
112 len = STRLITERALLEN("/lxc/lock/") + strlen(n) + strlen(p) + 3;
113
114 rundir = get_rundir();
115 if (!rundir)
116 return NULL;
117
118 len += strlen(rundir);
119
120 dest = malloc(len);
121 if (!dest) {
122 free(rundir);
123 return NULL;
124 }
125
126 ret = snprintf(dest, len, "%s/lxc/lock/%s", rundir, p);
127 if (ret < 0 || (size_t)ret >= len) {
128 free(dest);
129 free(rundir);
130 return NULL;
131 }
132
133 ret = mkdir_p(dest, 0755);
134 if (ret < 0) {
135 free(dest);
136 free(rundir);
137 return NULL;
138 }
139
140 ret = snprintf(dest, len, "%s/lxc/lock/%s/.%s", rundir, p, n);
141 free(rundir);
142 if (ret < 0 || (size_t)ret >= len) {
143 free(dest);
144 return NULL;
145 }
146
147 return dest;
148 }
149
150 static sem_t *lxc_new_unnamed_sem(void)
151 {
152 int ret;
153 sem_t *s;
154
155 s = malloc(sizeof(*s));
156 if (!s)
157 return NULL;
158
159 ret = sem_init(s, 0, 1);
160 if (ret < 0) {
161 free(s);
162 return NULL;
163 }
164
165 return s;
166 }
167
168 struct lxc_lock *lxc_newlock(const char *lxcpath, const char *name)
169 {
170 struct lxc_lock *l;
171
172 l = malloc(sizeof(*l));
173 if (!l)
174 goto on_error;
175
176 if (!name) {
177 l->type = LXC_LOCK_ANON_SEM;
178 l->u.sem = lxc_new_unnamed_sem();
179 if (!l->u.sem) {
180 free(l);
181 l = NULL;
182 }
183
184 goto on_error;
185 }
186
187 l->type = LXC_LOCK_FLOCK;
188 l->u.f.fname = lxclock_name(lxcpath, name);
189 if (!l->u.f.fname) {
190 free(l);
191 l = NULL;
192 goto on_error;
193 }
194
195 l->u.f.fd = -1;
196
197 on_error:
198 return l;
199 }
200
201 int lxclock(struct lxc_lock *l, int timeout)
202 {
203 struct flock lk;
204 int ret = -1, saved_errno = errno;
205
206 switch(l->type) {
207 case LXC_LOCK_ANON_SEM:
208 if (!timeout) {
209 ret = sem_wait(l->u.sem);
210 if (ret < 0)
211 saved_errno = errno;
212 } else {
213 struct timespec ts;
214
215 ret = clock_gettime(CLOCK_REALTIME, &ts);
216 if (ret < 0) {
217 ret = -2;
218 goto on_error;
219 }
220
221 ts.tv_sec += timeout;
222 ret = sem_timedwait(l->u.sem, &ts);
223 if (ret < 0)
224 saved_errno = errno;
225 }
226
227 break;
228 case LXC_LOCK_FLOCK:
229 ret = -2;
230 if (timeout) {
231 ERROR("Timeouts are not supported with file locks");
232 goto on_error;
233 }
234
235 if (!l->u.f.fname) {
236 ERROR("No filename set for file lock");
237 goto on_error;
238 }
239
240 if (l->u.f.fd == -1) {
241 l->u.f.fd = open(l->u.f.fname, O_CREAT | O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NOCTTY, S_IWUSR | S_IRUSR);
242 if (l->u.f.fd == -1) {
243 SYSERROR("Failed to open \"%s\"", l->u.f.fname);
244 saved_errno = errno;
245 goto on_error;
246 }
247 }
248
249 memset(&lk, 0, sizeof(struct flock));
250
251 lk.l_type = F_WRLCK;
252 lk.l_whence = SEEK_SET;
253
254 ret = fcntl(l->u.f.fd, F_OFD_SETLKW, &lk);
255 if (ret < 0) {
256 if (errno == EINVAL)
257 ret = flock(l->u.f.fd, LOCK_EX);
258 saved_errno = errno;
259 }
260
261 break;
262 }
263
264 on_error:
265 errno = saved_errno;
266 return ret;
267 }
268
269 int lxcunlock(struct lxc_lock *l)
270 {
271 struct flock lk;
272 int ret = 0, saved_errno = errno;
273
274 switch (l->type) {
275 case LXC_LOCK_ANON_SEM:
276 if (!l->u.sem) {
277 ret = -2;
278 } else {
279 ret = sem_post(l->u.sem);
280 saved_errno = errno;
281 }
282
283 break;
284 case LXC_LOCK_FLOCK:
285 if (l->u.f.fd != -1) {
286 memset(&lk, 0, sizeof(struct flock));
287
288 lk.l_type = F_UNLCK;
289 lk.l_whence = SEEK_SET;
290
291 ret = fcntl(l->u.f.fd, F_OFD_SETLK, &lk);
292 if (ret < 0) {
293 if (errno == EINVAL)
294 ret = flock(l->u.f.fd, LOCK_EX | LOCK_NB);
295 saved_errno = errno;
296 }
297
298 close(l->u.f.fd);
299 l->u.f.fd = -1;
300 } else {
301 ret = -2;
302 }
303
304 break;
305 }
306
307 errno = saved_errno;
308 return ret;
309 }
310
311 /*
312 * lxc_putlock() is only called when a container_new() fails,
313 * or during container_put(), which is already guaranteed to
314 * only be done by one task.
315 * So the only exclusion we need to provide here is for regular
316 * thread safety (i.e. file descriptor table changes).
317 */
318 void lxc_putlock(struct lxc_lock *l)
319 {
320 if (!l)
321 return;
322
323 switch(l->type) {
324 case LXC_LOCK_ANON_SEM:
325 if (l->u.sem) {
326 sem_destroy(l->u.sem);
327 free(l->u.sem);
328 l->u.sem = NULL;
329 }
330
331 break;
332 case LXC_LOCK_FLOCK:
333 if (l->u.f.fd != -1) {
334 close(l->u.f.fd);
335 l->u.f.fd = -1;
336 }
337
338 free(l->u.f.fname);
339 l->u.f.fname = NULL;
340
341 break;
342 }
343
344 free(l);
345 }
346
347 void process_lock(void)
348 {
349 lock_mutex(&thread_mutex);
350 }
351
352 void process_unlock(void)
353 {
354 unlock_mutex(&thread_mutex);
355 }
356
357 int container_mem_lock(struct lxc_container *c)
358 {
359 return lxclock(c->privlock, 0);
360 }
361
362 void container_mem_unlock(struct lxc_container *c)
363 {
364 lxcunlock(c->privlock);
365 }
366
367 int container_disk_lock(struct lxc_container *c)
368 {
369 int ret;
370
371 ret = lxclock(c->privlock, 0);
372 if (ret < 0)
373 return ret;
374
375 ret = lxclock(c->slock, 0);
376 if (ret < 0) {
377 lxcunlock(c->privlock);
378 return ret;
379 }
380
381 return 0;
382 }
383
384 void container_disk_unlock(struct lxc_container *c)
385 {
386 lxcunlock(c->slock);
387 lxcunlock(c->privlock);
388 }