From: Serge Hallyn Date: Mon, 16 Sep 2013 23:28:41 +0000 (-0500) Subject: make heavier use of process_lock (v2) X-Git-Tag: lxc-1.0.0.alpha2~110 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=025ed0f3911836b71f498d8368725c77a7e1932a;p=thirdparty%2Flxc.git make heavier use of process_lock (v2) pthread_mutex_lock() will only return an error if it was set to PTHREAD_MUTEX_ERRORCHECK and we are recursively calling it (and would otherwise have deadlocked). If that's the case then log a message for future debugging and exit. Trying to "recover" is nonsense at that point. process_lock() was held over too long a time in lxcapi_start() in the daemonize case. (note the non-daemonized case still needs a check to enforce that it must NOT be called while threaded). Add process_lock() at least across all open/close/socket() calls. Anything done after a fork() doesn't need the locks as it is no longer threaded - so some open/close/dups()s are not locked for that reason. However, some common functions are called from both threaded and non-threaded contexts. So after doing a fork(), do a possibly-extraneous process_unlock() to make sure that, if we were forked while pthread mutex was held, we aren't deadlocked by nobody. Tested that lp:~serge-hallyn/+junk/lxc-test still works with this patch. Signed-off-by: Serge Hallyn Tested-by: S.Çağlar Onur Acked-by: Stéphane Graber --- diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c index 204658d32..333f05eb3 100644 --- a/src/lxc/af_unix.c +++ b/src/lxc/af_unix.c @@ -30,6 +30,7 @@ #include #include "log.h" +#include "lxclock.h" lxc_log_define(lxc_af_unix, lxc); @@ -42,7 +43,9 @@ int lxc_af_unix_open(const char *path, int type, int flags) if (flags & O_TRUNC) unlink(path); + process_lock(); fd = socket(PF_UNIX, type, 0); + process_unlock(); if (fd < 0) return -1; @@ -57,7 +60,9 @@ int lxc_af_unix_open(const char *path, int type, int flags) if (path[0]) { len = strlen(path); if (len >= sizeof(addr.sun_path)) { + process_lock(); close(fd); + process_unlock(); errno = ENAMETOOLONG; return -1; } @@ -66,14 +71,18 @@ int lxc_af_unix_open(const char *path, int type, int flags) if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) { int tmp = errno; + process_lock(); close(fd); + process_unlock(); errno = tmp; return -1; } if (type == SOCK_STREAM && listen(fd, 100)) { int tmp = errno; + process_lock(); close(fd); + process_unlock(); errno = tmp; return -1; } @@ -90,7 +99,9 @@ int lxc_af_unix_close(int fd) addr.sun_path[0]) unlink(addr.sun_path); + process_lock(); close(fd); + process_unlock(); return 0; } @@ -100,7 +111,9 @@ int lxc_af_unix_connect(const char *path) int fd; struct sockaddr_un addr; + process_lock(); fd = socket(PF_UNIX, SOCK_STREAM, 0); + process_unlock(); if (fd < 0) return -1; @@ -113,7 +126,9 @@ int lxc_af_unix_connect(const char *path) if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) { int tmp = errno; + process_lock(); close(fd); + process_unlock(); errno = tmp; return -1; } diff --git a/src/lxc/apparmor.c b/src/lxc/apparmor.c index 4dad801ff..c31cce760 100644 --- a/src/lxc/apparmor.c +++ b/src/lxc/apparmor.c @@ -28,6 +28,7 @@ #include "log.h" #include "apparmor.h" +#include "lxclock.h" lxc_log_define(lxc_apparmor, lxc); @@ -53,7 +54,9 @@ extern char *aa_get_profile(pid_t pid) return NULL; } again: + process_lock(); f = fopen(path, "r"); + process_unlock(); if (!f) { SYSERROR("opening %s\n", path); if (buf) @@ -65,11 +68,15 @@ again: memset(buf, 0, sz); if (!buf) { ERROR("out of memory"); + process_lock(); fclose(f); + process_unlock(); return NULL; } ret = fread(buf, 1, sz - 1, f); + process_lock(); fclose(f); + process_unlock(); if (ret >= sz) goto again; if (ret < 0) { @@ -108,11 +115,15 @@ static int check_apparmor_enabled(void) ret = stat(AA_MOUNT_RESTR, &statbuf); if (ret != 0) return 0; + process_lock(); fin = fopen(AA_ENABLED_FILE, "r"); + process_unlock(); if (!fin) return 0; ret = fscanf(fin, "%c", &e); + process_lock(); fclose(fin); + process_unlock(); if (ret == 1 && e == 'Y') return 1; return 0; diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 6f3325237..cc95079a5 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -50,6 +50,7 @@ #include "utils.h" #include "commands.h" #include "cgroup.h" +#include "lxclock.h" #if HAVE_SYS_PERSONALITY_H #include @@ -78,7 +79,9 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) /* read capabilities */ snprintf(proc_fn, MAXPATHLEN, "/proc/%d/status", pid); + process_lock(); proc_file = fopen(proc_fn, "r"); + process_unlock(); if (!proc_file) { SYSERROR("Could not open %s", proc_fn); goto out_error; @@ -95,7 +98,9 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) if (line) free(line); + process_lock(); fclose(proc_file); + process_unlock(); if (!found) { SYSERROR("Could not read capability bounding set from %s", proc_fn); @@ -106,14 +111,18 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) /* read personality */ snprintf(proc_fn, MAXPATHLEN, "/proc/%d/personality", pid); + process_lock(); proc_file = fopen(proc_fn, "r"); + process_unlock(); if (!proc_file) { SYSERROR("Could not open %s", proc_fn); goto out_error; } ret = fscanf(proc_file, "%lx", &info->personality); + process_lock(); fclose(proc_file); + process_unlock(); if (ret == EOF || ret == 0) { SYSERROR("Could not read personality from %s", proc_fn); @@ -162,15 +171,19 @@ int lxc_attach_to_ns(pid_t pid, int which) } snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]); + process_lock(); fd[i] = open(path, O_RDONLY | O_CLOEXEC); + process_unlock(); if (fd[i] < 0) { saved_errno = errno; /* close all already opened file descriptors before * we return an error, so we don't leak them */ + process_lock(); for (j = 0; j < i; j++) close(fd[j]); + process_unlock(); errno = saved_errno; SYSERROR("failed to open '%s'", path); @@ -190,7 +203,9 @@ int lxc_attach_to_ns(pid_t pid, int which) return -1; } + process_lock(); close(fd[i]); + process_unlock(); } return 0; @@ -378,14 +393,18 @@ char *lxc_attach_getpwshell(uid_t uid) * getent program, and we need to capture its * output, so we use a pipe for that purpose */ + process_lock(); ret = pipe(pipes); + process_unlock(); if (ret < 0) return NULL; pid = fork(); if (pid < 0) { + process_lock(); close(pipes[0]); close(pipes[1]); + process_unlock(); return NULL; } @@ -397,9 +416,13 @@ char *lxc_attach_getpwshell(uid_t uid) int found = 0; int status; + process_lock(); close(pipes[1]); + process_unlock(); + process_lock(); pipe_f = fdopen(pipes[0], "r"); + process_unlock(); while (getline(&line, &line_bufsz, pipe_f) != -1) { char *token; char *saveptr = NULL; @@ -456,7 +479,9 @@ char *lxc_attach_getpwshell(uid_t uid) } free(line); + process_lock(); fclose(pipe_f); + process_unlock(); again: if (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) @@ -489,6 +514,7 @@ char *lxc_attach_getpwshell(uid_t uid) NULL }; + process_unlock(); // we're no longer sharing close(pipes[0]); /* we want to capture stdout */ @@ -651,7 +677,9 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun * close socket close socket * run program */ + process_lock(); ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); + process_unlock(); if (ret < 0) { SYSERROR("could not set up required IPC mechanism for attaching"); free(cwd); @@ -689,7 +717,9 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun /* inital thread, we close the socket that is for the * subprocesses */ + process_lock(); close(ipc_sockets[1]); + process_unlock(); free(cwd); /* get pid from intermediate process */ @@ -761,7 +791,9 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun /* now shut down communication with child, we're done */ shutdown(ipc_sockets[0], SHUT_RDWR); + process_lock(); close(ipc_sockets[0]); + process_unlock(); free(init_ctx->aa_profile); free(init_ctx); @@ -778,7 +810,9 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun * otherwise the pid we're waiting for may never exit */ shutdown(ipc_sockets[0], SHUT_RDWR); + process_lock(); close(ipc_sockets[0]); + process_unlock(); if (to_cleanup_pid) (void) wait_for_pid(to_cleanup_pid); free(init_ctx->aa_profile); @@ -786,6 +820,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun return -1; } + process_unlock(); // we're no longer sharing /* first subprocess begins here, we close the socket that is for the * initial thread */ diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c index b45f2cb06..b643bb7b5 100644 --- a/src/lxc/bdev.c +++ b/src/lxc/bdev.c @@ -70,6 +70,8 @@ static int do_rsync(const char *src, const char *dest) return -1; if (pid > 0) return wait_for_pid(pid); + + process_unlock(); // we're no longer sharing l = strlen(src) + 2; s = malloc(l); if (!s) @@ -93,11 +95,15 @@ static int blk_getsize(struct bdev *bdev, unsigned long *size) if (strcmp(bdev->type, "loop") == 0) path = bdev->src + 5; + process_lock(); fd = open(path, O_RDONLY); + process_unlock(); if (fd < 0) return -1; ret = ioctl(fd, BLKGETSIZE64, size); + process_lock(); close(fd); + process_unlock(); return ret; } @@ -194,6 +200,7 @@ static int do_mkfs(const char *path, const char *fstype) if (pid > 0) return wait_for_pid(pid); + process_unlock(); // we're no longer sharing // If the file is not a block device, we don't want mkfs to ask // us about whether to proceed. close(0); @@ -252,16 +259,23 @@ static int detect_fs(struct bdev *bdev, char *type, int len) if (strcmp(bdev->type, "loop") == 0) srcdev = bdev->src + 5; - if (pipe(p) < 0) + process_lock(); + ret = pipe(p); + process_unlock(); + if (ret < 0) return -1; if ((pid = fork()) < 0) return -1; if (pid > 0) { int status; + process_lock(); close(p[1]); + process_unlock(); memset(type, 0, len); ret = read(p[0], type, len-1); + process_lock(); close(p[0]); + process_unlock(); if (ret < 0) { SYSERROR("error reading from pipe"); wait(&status); @@ -277,6 +291,7 @@ static int detect_fs(struct bdev *bdev, char *type, int len) return ret; } + process_unlock(); // we're no longer sharing if (unshare(CLONE_NEWNS) < 0) exit(1); @@ -488,7 +503,10 @@ static int zfs_list_entry(const char *path, char *output, size_t inlen) FILE *f; int found=0; - if ((f = popen("zfs list 2> /dev/null", "r")) == NULL) { + process_lock(); + f = popen("zfs list 2> /dev/null", "r"); + process_unlock(); + if (f == NULL) { SYSERROR("popen failed"); return 0; } @@ -498,7 +516,9 @@ static int zfs_list_entry(const char *path, char *output, size_t inlen) break; } } + process_lock(); (void) pclose(f); + process_unlock(); return found; } @@ -566,6 +586,8 @@ static int zfs_clone(const char *opath, const char *npath, const char *oname, return -1; if (!pid) { char dev[MAXPATHLEN]; + + process_unlock(); // we're no longer sharing ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, nname); if (ret < 0 || ret >= MAXPATHLEN) exit(1); @@ -589,6 +611,7 @@ static int zfs_clone(const char *opath, const char *npath, const char *oname, if ((pid = fork()) < 0) return -1; if (!pid) { + process_unlock(); // we're no longer sharing execlp("zfs", "zfs", "destroy", path1, NULL); exit(1); } @@ -599,6 +622,7 @@ static int zfs_clone(const char *opath, const char *npath, const char *oname, if ((pid = fork()) < 0) return -1; if (!pid) { + process_unlock(); // we're no longer sharing execlp("zfs", "zfs", "snapshot", path1, NULL); exit(1); } @@ -609,6 +633,7 @@ static int zfs_clone(const char *opath, const char *npath, const char *oname, if ((pid = fork()) < 0) return -1; if (!pid) { + process_unlock(); // we're no longer sharing execlp("zfs", "zfs", "clone", option, path1, path2, NULL); exit(1); } @@ -659,6 +684,7 @@ static int zfs_destroy(struct bdev *orig) if (pid) return wait_for_pid(pid); + process_unlock(); // we're no longer sharing if (!zfs_list_entry(orig->src, output, MAXPATHLEN)) { ERROR("Error: zfs entry for %s not found", orig->src); return -1; @@ -703,6 +729,7 @@ static int zfs_create(struct bdev *bdev, const char *dest, const char *n, if (pid) return wait_for_pid(pid); + process_unlock(); // we're no longer sharing char dev[MAXPATHLEN]; ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, n); if (ret < 0 || ret >= MAXPATHLEN) @@ -750,11 +777,15 @@ static int lvm_detect(const char *path) ERROR("lvm uuid pathname too long"); return 0; } + process_lock(); fout = fopen(devp, "r"); + process_unlock(); if (!fout) return 0; ret = fread(buf, 1, 4, fout); + process_lock(); fclose(fout); + process_unlock(); if (ret != 4 || strncmp(buf, "LVM-", 4) != 0) return 0; return 1; @@ -797,6 +828,7 @@ static int do_lvm_create(const char *path, unsigned long size) if (pid > 0) return wait_for_pid(pid); + process_unlock(); // we're no longer sharing // lvcreate default size is in M, not bytes. ret = snprintf(sz, 24, "%lu", size/1000000); if (ret < 0 || ret >= 24) @@ -832,6 +864,8 @@ static int lvm_snapshot(const char *orig, const char *path, unsigned long size) } if (pid > 0) return wait_for_pid(pid); + + process_unlock(); // we're no longer sharing // lvcreate default size is in M, not bytes. ret = snprintf(sz, 24, "%lu", size/1000000); if (ret < 0 || ret >= 24) @@ -952,6 +986,7 @@ static int lvm_destroy(struct bdev *orig) if ((pid = fork()) < 0) return -1; if (!pid) { + process_unlock(); // we're no longer sharing execlp("lvremove", "lvremove", "-f", orig->src, NULL); exit(1); } @@ -1052,13 +1087,17 @@ static bool is_btrfs_fs(const char *path) struct btrfs_ioctl_space_args sargs; // make sure this is a btrfs filesystem + process_lock(); fd = open(path, O_RDONLY); + process_unlock(); if (fd < 0) return false; sargs.space_slots = 0; sargs.total_spaces = 0; ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, &sargs); + process_lock(); close(fd); + process_unlock(); if (ret < 0) return false; @@ -1155,7 +1194,10 @@ static int btrfs_subvolume_create(const char *path) } *p = '\0'; - if ((fd = open(newfull, O_RDONLY)) < 0) { + process_lock(); + fd = open(newfull, O_RDONLY); + process_unlock(); + if (fd < 0) { ERROR("Error opening %s", newfull); free(newfull); return -1; @@ -1168,7 +1210,9 @@ static int btrfs_subvolume_create(const char *path) INFO("btrfs: snapshot create ioctl returned %d", ret); free(newfull); + process_lock(); close(fd); + process_unlock(); return ret; } @@ -1190,12 +1234,14 @@ static int btrfs_snapshot(const char *orig, const char *new) } newname = basename(newfull); newdir = dirname(newfull); + process_lock(); fd = open(orig, O_RDONLY); + fddst = open(newdir, O_RDONLY); + process_unlock(); if (fd < 0) { SYSERROR("Error opening original rootfs %s", orig); goto out; } - fddst = open(newdir, O_RDONLY); if (fddst < 0) { SYSERROR("Error opening new container dir %s", newdir); goto out; @@ -1209,10 +1255,12 @@ static int btrfs_snapshot(const char *orig, const char *new) INFO("btrfs: snapshot create ioctl returned %d", ret); out: + process_lock(); if (fddst != -1) close(fddst); if (fd != -1) close(fd); + process_unlock(); if (newfull) free(newfull); return ret; @@ -1282,7 +1330,10 @@ static int btrfs_destroy(struct bdev *orig) } *p = '\0'; - if ((fd = open(newfull, O_RDONLY)) < 0) { + process_lock(); + fd = open(newfull, O_RDONLY); + process_unlock(); + if (fd < 0) { ERROR("Error opening %s", newfull); free(newfull); return -1; @@ -1295,7 +1346,9 @@ static int btrfs_destroy(struct bdev *orig) INFO("btrfs: snapshot create ioctl returned %d", ret); free(newfull); + process_lock(); close(fd); + process_unlock(); return ret; } @@ -1335,7 +1388,10 @@ static int find_free_loopdev(int *retfd, char *namep) DIR *dir; int fd = -1; - if (!(dir = opendir("/dev"))) { + process_lock(); + dir = opendir("/dev"); + process_unlock(); + if (!dir) { SYSERROR("Error opening /dev"); return -1; } @@ -1345,10 +1401,15 @@ static int find_free_loopdev(int *retfd, char *namep) break; if (strncmp(direntp->d_name, "loop", 4) != 0) continue; - if ((fd = openat(dirfd(dir), direntp->d_name, O_RDWR)) < 0) + process_lock(); + fd = openat(dirfd(dir), direntp->d_name, O_RDWR); + process_unlock(); + if (fd < 0) continue; if (ioctl(fd, LOOP_GET_STATUS64, &lo) == 0 || errno != ENXIO) { + process_lock(); close(fd); + process_unlock(); fd = -1; continue; } @@ -1356,7 +1417,9 @@ static int find_free_loopdev(int *retfd, char *namep) snprintf(namep, 100, "/dev/%s", direntp->d_name); break; } + process_lock(); closedir(dir); + process_unlock(); if (fd == -1) { ERROR("No loop device found"); return -1; @@ -1379,7 +1442,10 @@ static int loop_mount(struct bdev *bdev) if (find_free_loopdev(&lfd, loname) < 0) return -22; - if ((ffd = open(bdev->src + 5, O_RDWR)) < 0) { + process_lock(); + ffd = open(bdev->src + 5, O_RDWR); + process_unlock(); + if (ffd < 0) { SYSERROR("Error opening backing file %s\n", bdev->src); goto out; } @@ -1402,12 +1468,14 @@ static int loop_mount(struct bdev *bdev) bdev->lofd = lfd; out: + process_lock(); if (ffd > -1) close(ffd); if (ret < 0) { close(lfd); bdev->lofd = -1; } + process_unlock(); return ret; } @@ -1421,7 +1489,9 @@ static int loop_umount(struct bdev *bdev) return -22; ret = umount(bdev->dest); if (bdev->lofd >= 0) { + process_lock(); close(bdev->lofd); + process_unlock(); bdev->lofd = -1; } return ret; @@ -1429,9 +1499,11 @@ static int loop_umount(struct bdev *bdev) static int do_loop_create(const char *path, unsigned long size, const char *fstype) { - int fd; + int fd, ret; // create the new loopback file. + process_lock(); fd = creat(path, S_IRUSR|S_IWUSR); + process_unlock(); if (fd < 0) return -1; if (lseek(fd, size, SEEK_SET) < 0) { @@ -1444,7 +1516,10 @@ static int do_loop_create(const char *path, unsigned long size, const char *fsty close(fd); return -1; } - if (close(fd) < 0) { + process_lock(); + ret = close(fd); + process_unlock(); + if (ret < 0) { SYSERROR("Error closing new loop file"); return -1; } @@ -1975,6 +2050,7 @@ struct bdev *bdev_copy(const char *src, const char *oldname, const char *cname, return new; } + process_unlock(); // we're no longer sharing if (unshare(CLONE_NEWNS) < 0) { SYSERROR("unshare CLONE_NEWNS"); exit(1); diff --git a/src/lxc/caps.c b/src/lxc/caps.c index 006172d1d..bcbb859ff 100644 --- a/src/lxc/caps.c +++ b/src/lxc/caps.c @@ -31,6 +31,7 @@ #include "config.h" #include "log.h" +#include "lxclock.h" lxc_log_define(lxc_caps, lxc); @@ -191,7 +192,9 @@ static int _real_caps_last_cap(void) /* try to get the maximum capability over the kernel * interface introduced in v3.2 */ + process_lock(); fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY); + process_unlock(); if (fd >= 0) { char buf[32]; char *ptr; @@ -205,7 +208,9 @@ static int _real_caps_last_cap(void) result = -1; } + process_lock(); close(fd); + process_unlock(); } /* try to get it manually by trying to get the status of diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c index 9417e7769..fe1a4c357 100644 --- a/src/lxc/cgroup.c +++ b/src/lxc/cgroup.c @@ -45,6 +45,7 @@ #include "conf.h" #include "utils.h" #include "bdev.h" +#include "lxclock.h" #include #include @@ -148,7 +149,9 @@ struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist) meta_data->ref = 1; /* Step 1: determine all kernel subsystems */ + process_lock(); proc_cgroups = fopen_cloexec("/proc/cgroups", "r"); + process_unlock(); if (!proc_cgroups) goto out_error; @@ -186,18 +189,22 @@ struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist) kernel_subsystems_count++; } + process_lock(); fclose(proc_cgroups); + process_unlock(); proc_cgroups = NULL; /* Step 2: determine all hierarchies (by reading /proc/self/cgroup), * since mount points don't specify hierarchy number and * /proc/cgroups does not contain named hierarchies */ + process_lock(); proc_self_cgroup = fopen_cloexec("/proc/self/cgroup", "r"); /* if for some reason (because of setns() and pid namespace for example), * /proc/self is not valid, we try /proc/1/cgroup... */ if (!proc_self_cgroup) proc_self_cgroup = fopen_cloexec("/proc/1/cgroup", "r"); + process_unlock(); if (!proc_self_cgroup) goto out_error; @@ -274,15 +281,19 @@ struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist) } } + process_lock(); fclose(proc_self_cgroup); + process_unlock(); proc_self_cgroup = NULL; /* Step 3: determine all mount points of each hierarchy */ + process_lock(); proc_self_mountinfo = fopen_cloexec("/proc/self/mountinfo", "r"); /* if for some reason (because of setns() and pid namespace for example), * /proc/self is not valid, we try /proc/1/cgroup... */ if (!proc_self_mountinfo) proc_self_mountinfo = fopen_cloexec("/proc/1/mountinfo", "r"); + process_unlock(); if (!proc_self_mountinfo) goto out_error; @@ -395,12 +406,14 @@ struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist) out_error: saved_errno = errno; + process_lock(); if (proc_cgroups) fclose(proc_cgroups); if (proc_self_cgroup) fclose(proc_self_cgroup); if (proc_self_mountinfo) fclose(proc_self_mountinfo); + process_unlock(); free(line); free(tokens); lxc_free_array((void **)kernel_subsystems, free); @@ -1367,7 +1380,9 @@ struct cgroup_process_info *lxc_cgroup_process_info_getx(const char *proc_pid_cg struct cgroup_process_info **cptr = &result; struct cgroup_process_info *entry = NULL; + process_lock(); proc_pid_cgroup = fopen_cloexec(proc_pid_cgroup_str, "r"); + process_unlock(); if (!proc_pid_cgroup) return NULL; @@ -1437,14 +1452,18 @@ struct cgroup_process_info *lxc_cgroup_process_info_getx(const char *proc_pid_cg entry = NULL; } + process_lock(); fclose(proc_pid_cgroup); + process_unlock(); free(line); return result; out_error: saved_errno = errno; + process_lock(); if (proc_pid_cgroup) fclose(proc_pid_cgroup); + process_unlock(); lxc_cgroup_process_info_free(result); lxc_cgroup_process_info_free(entry); free(line); @@ -1702,7 +1721,9 @@ bool cgroup_devices_has_allow_or_deny(struct lxc_handler *h, char *v, bool for_a return false; } + process_lock(); devices_list = fopen_cloexec(path, "r"); + process_unlock(); if (!devices_list) { free(path); return false; @@ -1722,7 +1743,9 @@ bool cgroup_devices_has_allow_or_deny(struct lxc_handler *h, char *v, bool for_a } out: + process_lock(); fclose(devices_list); + process_unlock(); free(line); free(path); return ret; @@ -1744,7 +1767,9 @@ int cgroup_recursive_task_count(const char *cgroup_path) if (!dent_buf) return -1; + process_lock(); d = opendir(cgroup_path); + process_unlock(); if (!d) return 0; @@ -1761,13 +1786,17 @@ int cgroup_recursive_task_count(const char *cgroup_path) continue; sub_path = lxc_string_join("/", parts, false); if (!sub_path) { + process_lock(); closedir(d); + process_unlock(); free(dent_buf); return -1; } r = stat(sub_path, &st); if (r < 0) { + process_lock(); closedir(d); + process_unlock(); free(dent_buf); free(sub_path); return -1; @@ -1783,7 +1812,9 @@ int cgroup_recursive_task_count(const char *cgroup_path) } free(sub_path); } + process_lock(); closedir(d); + process_unlock(); free(dent_buf); return n; @@ -1796,7 +1827,9 @@ int count_lines(const char *fn) size_t sz = 0; int n = 0; + process_lock(); f = fopen_cloexec(fn, "r"); + process_unlock(); if (!f) return -1; @@ -1804,7 +1837,9 @@ int count_lines(const char *fn) n++; } free(line); + process_lock(); fclose(f); + process_unlock(); return n; } diff --git a/src/lxc/commands.c b/src/lxc/commands.c index f12ae2dec..f481a55ce 100644 --- a/src/lxc/commands.c +++ b/src/lxc/commands.c @@ -46,6 +46,7 @@ #include "mainloop.h" #include "af_unix.h" #include "config.h" +#include "lxclock.h" /* * This file provides the different functions for clients to @@ -716,7 +717,9 @@ static void lxc_cmd_fd_cleanup(int fd, struct lxc_handler *handler, { lxc_console_free(handler->conf, fd); lxc_mainloop_del_handler(descr, fd); + process_lock(); close(fd); + process_unlock(); } static int lxc_cmd_handler(int fd, void *data, struct lxc_epoll_descr *descr) @@ -787,7 +790,9 @@ static int lxc_cmd_accept(int fd, void *data, struct lxc_epoll_descr *descr) { int opt = 1, ret = -1, connection; + process_lock(); connection = accept(fd, NULL, 0); + process_unlock(); if (connection < 0) { SYSERROR("failed to accept connection"); return -1; @@ -814,7 +819,9 @@ out: return ret; out_close: + process_lock(); close(connection); + process_unlock(); goto out; } @@ -843,7 +850,9 @@ int lxc_cmd_init(const char *name, struct lxc_handler *handler, if (fcntl(fd, F_SETFD, FD_CLOEXEC)) { SYSERROR("failed to set sigfd to close-on-exec"); + process_lock(); close(fd); + process_unlock(); return -1; } @@ -860,7 +869,9 @@ int lxc_cmd_mainloop_add(const char *name, ret = lxc_mainloop_add_handler(descr, fd, lxc_cmd_accept, handler); if (ret) { ERROR("failed to add handler for command socket"); + process_lock(); close(fd); + process_unlock(); } return ret; diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 79220d1ff..e933c9a3a 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -73,6 +73,7 @@ #include "caps.h" /* for lxc_caps_last_cap() */ #include "bdev.h" #include "cgroup.h" +#include "lxclock.h" #if HAVE_APPARMOR #include @@ -296,11 +297,15 @@ static char *mkifname(char *template) getifaddrs(&ifaddr); /* Initialize the random number generator */ + process_lock(); urandom = fopen ("/dev/urandom", "r"); + process_unlock(); if (urandom != NULL) { if (fread (&seed, sizeof(seed), 1, urandom) <= 0) seed = time(0); + process_lock(); fclose(urandom); + process_unlock(); } else seed = time(0); @@ -350,7 +355,9 @@ static int run_buffer(char *buffer) char *output; int ret; + process_lock(); f = popen(buffer, "r"); + process_unlock(); if (!f) { SYSERROR("popen failed"); return -1; @@ -359,7 +366,9 @@ static int run_buffer(char *buffer) output = malloc(LXC_LOG_BUFFER_SIZE); if (!output) { ERROR("failed to allocate memory for script output"); + process_lock(); pclose(f); + process_unlock(); return -1; } @@ -368,7 +377,9 @@ static int run_buffer(char *buffer) free(output); + process_lock(); ret = pclose(f); + process_unlock(); if (ret == -1) { SYSERROR("Script exited on error"); return -1; @@ -573,7 +584,9 @@ static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo) int rfd; int ret = -1; + process_lock(); rfd = open(rootfs, O_RDWR); + process_unlock(); if (rfd < 0) { SYSERROR("failed to open '%s'", rootfs); return -1; @@ -595,7 +608,9 @@ static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo) ret = 0; out: + process_lock(); close(rfd); + process_unlock(); return ret; } @@ -608,7 +623,9 @@ static int mount_rootfs_file(const char *rootfs, const char *target) DIR *dir; char path[MAXPATHLEN]; + process_lock(); dir = opendir("/dev"); + process_unlock(); if (!dir) { SYSERROR("failed to open '/dev'"); return -1; @@ -632,19 +649,25 @@ static int mount_rootfs_file(const char *rootfs, const char *target) if (rc < 0 || rc >= MAXPATHLEN) continue; + process_lock(); fd = open(path, O_RDWR); + process_unlock(); if (fd < 0) continue; if (ioctl(fd, LOOP_GET_STATUS64, &loinfo) == 0) { + process_lock(); close(fd); + process_unlock(); continue; } if (errno != ENXIO) { WARN("unexpected error for ioctl on '%s': %m", direntp->d_name); + process_lock(); close(fd); + process_unlock(); continue; } @@ -653,13 +676,17 @@ static int mount_rootfs_file(const char *rootfs, const char *target) ret = setup_lodev(rootfs, fd, &loinfo); if (!ret) ret = mount_unknow_fs(path, target, 0); + process_lock(); close(fd); + process_unlock(); break; } + process_lock(); if (closedir(dir)) WARN("failed to close directory"); + process_unlock(); return ret; } @@ -705,7 +732,9 @@ int pin_rootfs(const char *rootfs) if (ret >= MAXPATHLEN) return -1; + process_lock(); fd = open(absrootfspin, O_CREAT | O_RDWR, S_IWUSR|S_IRUSR); + process_unlock(); if (fd < 0) return fd; (void)unlink(absrootfspin); @@ -881,13 +910,17 @@ static int setup_tty(const struct lxc_rootfs *rootfs, ERROR("pathname too long for ttys"); return -1; } + process_lock(); ret = creat(lxcpath, 0660); + process_unlock(); if (ret==-1 && errno != EEXIST) { SYSERROR("error creating %s\n", lxcpath); return -1; } + process_lock(); if (ret >= 0) close(ret); + process_unlock(); ret = unlink(path); if (ret && errno != ENOENT) { SYSERROR("error unlinking %s\n", path); @@ -913,12 +946,17 @@ static int setup_tty(const struct lxc_rootfs *rootfs, } else { /* If we populated /dev, then we need to create /dev/ttyN */ if (access(path, F_OK)) { + process_lock(); ret = creat(path, 0660); + process_unlock(); if (ret==-1) { SYSERROR("error creating %s\n", path); /* this isn't fatal, continue */ - } else + } else { + process_lock(); close(ret); + process_unlock(); + } } if (mount(pty_info->name, path, "none", MS_BIND, 0)) { WARN("failed to mount '%s'->'%s'", @@ -1226,7 +1264,9 @@ int detect_shared_rootfs(void) int i; char *p2; + process_lock(); f = fopen("/proc/self/mountinfo", "r"); + process_unlock(); if (!f) return 0; while ((p = fgets(buf, LINELEN, f))) { @@ -1244,12 +1284,16 @@ int detect_shared_rootfs(void) // this is '/'. is it shared? p = index(p2+1, ' '); if (p && strstr(p, "shared:")) { + process_lock(); fclose(f); + process_unlock(); return 1; } } } + process_lock(); fclose(f); + process_unlock(); return 0; } @@ -1505,13 +1549,17 @@ static int setup_ttydir_console(const struct lxc_rootfs *rootfs, return -1; } + process_lock(); ret = creat(lxcpath, 0660); + process_unlock(); if (ret==-1 && errno != EEXIST) { SYSERROR("error %d creating %s\n", errno, lxcpath); return -1; } + process_lock(); if (ret >= 0) close(ret); + process_unlock(); if (console->master < 0) { INFO("no console"); @@ -1827,7 +1875,9 @@ static int setup_mount(const struct lxc_rootfs *rootfs, const char *fstab, if (!fstab) return 0; + process_lock(); file = setmntent(fstab, "r"); + process_unlock(); if (!file) { SYSERROR("failed to use '%s'", fstab); return -1; @@ -1835,7 +1885,9 @@ static int setup_mount(const struct lxc_rootfs *rootfs, const char *fstab, ret = mount_file_entries(rootfs, file, lxc_name); + process_lock(); endmntent(file); + process_unlock(); return ret; } @@ -1847,7 +1899,9 @@ static int setup_mount_entries(const struct lxc_rootfs *rootfs, struct lxc_list char *mount_entry; int ret; + process_lock(); file = tmpfile(); + process_unlock(); if (!file) { ERROR("tmpfile error: %m"); return -1; @@ -1862,7 +1916,9 @@ static int setup_mount_entries(const struct lxc_rootfs *rootfs, struct lxc_list ret = mount_file_entries(rootfs, file, lxc_name); + process_lock(); fclose(file); + process_unlock(); return ret; } @@ -2007,14 +2063,18 @@ static int setup_hw_addr(char *hwaddr, const char *ifname) memcpy(ifr.ifr_name, ifname, IFNAMSIZ); memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr)); + process_lock(); fd = socket(AF_INET, SOCK_DGRAM, 0); + process_unlock(); if (fd < 0) { ERROR("socket failure : %s", strerror(errno)); return -1; } ret = ioctl(fd, SIOCSIFHWADDR, &ifr); + process_lock(); close(fd); + process_unlock(); if (ret) ERROR("ioctl failure : %s", strerror(errno)); @@ -2261,20 +2321,26 @@ static int setup_private_host_hw_addr(char *veth1) int err; int sockfd; + process_lock(); sockfd = socket(AF_INET, SOCK_DGRAM, 0); + process_unlock(); if (sockfd < 0) return -errno; snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1); err = ioctl(sockfd, SIOCGIFHWADDR, &ifr); if (err < 0) { + process_lock(); close(sockfd); + process_unlock(); return -errno; } ifr.ifr_hwaddr.sa_data[0] = 0xfe; err = ioctl(sockfd, SIOCSIFHWADDR, &ifr); + process_lock(); close(sockfd); + process_unlock(); if (err < 0) return -errno; @@ -2716,7 +2782,9 @@ static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, fprintf(stderr, "%s: path name too long", __func__); return -E2BIG; } + process_lock(); f = fopen(path, "w"); + process_unlock(); if (!f) { perror("open"); return -EINVAL; @@ -2724,7 +2792,9 @@ static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, ret = fwrite(buf, buf_size, 1, f); if (ret < 0) SYSERROR("writing id mapping"); + process_lock(); closeret = fclose(f); + process_unlock(); if (closeret) SYSERROR("writing id mapping"); return ret < 0 ? ret : closeret; @@ -2822,7 +2892,7 @@ int lxc_find_gateway_addresses(struct lxc_handler *handler) int lxc_create_tty(const char *name, struct lxc_conf *conf) { struct lxc_tty_info *tty_info = &conf->tty_info; - int i; + int i, ret; /* no tty in the configuration */ if (!conf->tty) @@ -2839,8 +2909,11 @@ int lxc_create_tty(const char *name, struct lxc_conf *conf) struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; - if (openpty(&pty_info->master, &pty_info->slave, - pty_info->name, NULL, NULL)) { + process_lock(); + ret = openpty(&pty_info->master, &pty_info->slave, + pty_info->name, NULL, NULL); + process_unlock(); + if (ret) { SYSERROR("failed to create pty #%d", i); tty_info->nbtty = i; lxc_delete_tty(tty_info); @@ -2871,8 +2944,10 @@ void lxc_delete_tty(struct lxc_tty_info *tty_info) for (i = 0; i < tty_info->nbtty; i++) { struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; + process_lock(); close(pty_info->master); close(pty_info->slave); + process_unlock(); } free(tty_info->pty_info); diff --git a/src/lxc/console.c b/src/lxc/console.c index e35a811aa..a32e9cfa0 100644 --- a/src/lxc/console.c +++ b/src/lxc/console.c @@ -100,16 +100,16 @@ static void lxc_console_winch(struct lxc_tty_state *ts) void lxc_console_sigwinch(int sig) { - if (process_lock() == 0) { - struct lxc_list *it; - struct lxc_tty_state *ts; + struct lxc_list *it; + struct lxc_tty_state *ts; - lxc_list_for_each(it, &lxc_ttys) { - ts = it->elem; - lxc_console_winch(ts); - } - process_unlock(); + process_lock(); + + lxc_list_for_each(it, &lxc_ttys) { + ts = it->elem; + lxc_console_winch(ts); } + process_unlock(); } static int lxc_console_cb_sigwinch_fd(int fd, void *cbdata, @@ -204,8 +204,11 @@ out: */ static void lxc_console_sigwinch_fini(struct lxc_tty_state *ts) { - if (ts->sigfd >= 0) + if (ts->sigfd >= 0) { + process_lock(); close(ts->sigfd); + process_unlock(); + } lxc_list_del(&ts->node); sigprocmask(SIG_SETMASK, &ts->oldmask, NULL); free(ts); @@ -227,7 +230,9 @@ static int lxc_console_cb_con(int fd, void *data, if (!r) { INFO("console client on fd %d has exited", fd); lxc_mainloop_del_handler(descr, fd); + process_lock(); close(fd); + process_unlock(); return 0; } @@ -343,8 +348,10 @@ static void lxc_console_peer_proxy_free(struct lxc_console *console) lxc_console_sigwinch_fini(console->tty_state); console->tty_state = NULL; } + process_lock(); close(console->peerpty.master); close(console->peerpty.slave); + process_unlock(); console->peerpty.master = -1; console->peerpty.slave = -1; console->peerpty.busy = -1; @@ -356,6 +363,7 @@ static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd) { struct termios oldtermio; struct lxc_tty_state *ts; + int ret; if (console->master < 0) { ERROR("console not set up"); @@ -373,8 +381,11 @@ static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd) /* this is the proxy pty that will be given to the client, and that * the real pty master will send to / recv from */ - if (openpty(&console->peerpty.master, &console->peerpty.slave, - console->peerpty.name, NULL, NULL)) { + process_lock(); + ret = openpty(&console->peerpty.master, &console->peerpty.slave, + console->peerpty.name, NULL, NULL); + process_unlock(); + if (ret) { SYSERROR("failed to create proxy pty"); return -1; } @@ -488,19 +499,23 @@ static void lxc_console_peer_default(struct lxc_console *console) */ if (!path && !access("/dev/tty", F_OK)) { int fd; + process_lock(); fd = open("/dev/tty", O_RDWR); if (fd >= 0) { close(fd); path = "/dev/tty"; } + process_unlock(); } if (!path) goto out; DEBUG("opening %s for console peer", path); + process_lock(); console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600)); + process_unlock(); if (console->peer < 0) goto out; @@ -531,7 +546,9 @@ err2: free(console->tios); console->tios = NULL; err1: + process_lock(); close(console->peer); + process_unlock(); console->peer = -1; out: DEBUG("no console peer"); @@ -545,24 +562,24 @@ void lxc_console_delete(struct lxc_console *console) free(console->tios); console->tios = NULL; + process_lock(); close(console->peer); - console->peer = -1; - - if (console->log_fd >= 0) { + close(console->master); + close(console->slave); + if (console->log_fd >= 0) close(console->log_fd); - console->log_fd = -1; - } + process_unlock(); - close(console->master); + console->peer = -1; console->master = -1; - - close(console->slave); console->slave = -1; + console->log_fd = -1; } int lxc_console_create(struct lxc_conf *conf) { struct lxc_console *console = &conf->console; + int ret; if (conf->is_execute) { INFO("no console for lxc-execute."); @@ -575,8 +592,11 @@ int lxc_console_create(struct lxc_conf *conf) if (console->path && !strcmp(console->path, "none")) return 0; - if (openpty(&console->master, &console->slave, - console->name, NULL, NULL)) { + process_lock(); + ret = openpty(&console->master, &console->slave, + console->name, NULL, NULL); + process_unlock(); + if (ret) { SYSERROR("failed to allocate a pty"); return -1; } @@ -594,9 +614,11 @@ int lxc_console_create(struct lxc_conf *conf) lxc_console_peer_default(console); if (console->log_path) { + process_lock(); console->log_fd = lxc_unpriv(open(console->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600)); + process_unlock(); if (console->log_fd < 0) { SYSERROR("failed to open '%s'", console->log_path); goto err; @@ -693,6 +715,7 @@ int lxc_console(struct lxc_container *c, int ttynum, process_lock(); ttyfd = lxc_cmd_console(c->name, &ttynum, &masterfd, c->config_path); + process_unlock(); if (ttyfd < 0) { ret = ttyfd; goto err1; @@ -747,9 +770,9 @@ int lxc_console(struct lxc_container *c, int ttynum, goto err4; } - process_unlock(); - ret = lxc_mainloop(&descr, -1); process_lock(); + ret = lxc_mainloop(&descr, -1); + process_unlock(); if (ret) { ERROR("mainloop returned an error"); goto err4; @@ -762,11 +785,12 @@ err4: err3: lxc_console_sigwinch_fini(ts); err2: + process_lock(); close(masterfd); close(ttyfd); + process_unlock(); err1: tcsetattr(stdinfd, TCSAFLUSH, &oldtios); - process_unlock(); return ret; } diff --git a/src/lxc/freezer.c b/src/lxc/freezer.c index be97d757e..41dc61e84 100644 --- a/src/lxc/freezer.c +++ b/src/lxc/freezer.c @@ -34,6 +34,7 @@ #include "error.h" #include "state.h" #include "monitor.h" +#include "lxclock.h" #include #include @@ -52,7 +53,9 @@ static int do_unfreeze(const char *nsgroup, int freeze, const char *name, const return -1; } + process_lock(); fd = open(freezer, O_RDWR); + process_unlock(); if (fd < 0) { SYSERROR("failed to open freezer at '%s'", nsgroup); return -1; @@ -114,7 +117,9 @@ static int do_unfreeze(const char *nsgroup, int freeze, const char *name, const } out: + process_lock(); close(fd); + process_unlock(); return ret; } diff --git a/src/lxc/log.c b/src/lxc/log.c index 9bbaa69fc..2da8b3224 100644 --- a/src/lxc/log.c +++ b/src/lxc/log.c @@ -36,6 +36,7 @@ #include "log.h" #include "caps.h" #include "utils.h" +#include "lxclock.h" #define LXC_LOG_PREFIX_SIZE 32 #define LXC_LOG_BUFFER_SIZE 512 @@ -159,8 +160,10 @@ static int log_open(const char *name) int fd; int newfd; + process_lock(); fd = lxc_unpriv(open(name, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0666)); + process_unlock(); if (fd == -1) { ERROR("failed to open log file \"%s\" : %s", name, strerror(errno)); @@ -174,7 +177,9 @@ static int log_open(const char *name) if (newfd == -1) ERROR("failed to dup log fd %d : %s", fd, strerror(errno)); + process_lock(); close(fd); + process_unlock(); return newfd; } @@ -241,7 +246,9 @@ static int __lxc_log_set_file(const char *fname, int create_dirs) { if (lxc_log_fd != -1) { // we are overriding the default. + process_lock(); close(lxc_log_fd); + process_unlock(); free(log_fname); } diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 79237dff4..d77ce37ba 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -100,12 +100,12 @@ int ongoing_create(struct lxc_container *c) if (!file_exists(path)) return 0; - if (process_lock()) - return -1; - if ((fd = open(path, O_RDWR)) < 0) { + process_lock(); + fd = open(path, O_RDWR); + process_unlock(); + if (fd < 0) { // give benefit of the doubt SYSERROR("Error opening partial file"); - process_unlock(); return 0; } lk.l_type = F_WRLCK; @@ -115,11 +115,13 @@ int ongoing_create(struct lxc_container *c) lk.l_pid = -1; if (fcntl(fd, F_GETLK, &lk) == 0 && lk.l_pid != -1) { // create is still ongoing + process_lock(); close(fd); process_unlock(); return 1; } // create completed but partial is still there. + process_lock(); close(fd); process_unlock(); return 2; @@ -138,8 +140,7 @@ int create_partial(struct lxc_container *c) ERROR("Error writing partial pathname"); return -1; } - if (process_lock()) - return -1; + process_lock(); if ((fd=open(path, O_RDWR | O_CREAT | O_EXCL, 0755)) < 0) { SYSERROR("Erorr creating partial file"); process_unlock(); @@ -167,17 +168,16 @@ void remove_partial(struct lxc_container *c, int fd) char *path = alloca(len); int ret; + process_lock(); close(fd); + process_unlock(); ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name); if (ret < 0 || ret >= len) { ERROR("Error writing partial pathname"); return; } - if (process_lock()) - return; if (unlink(path) < 0) SYSERROR("Error unlink partial file %s", path); - process_unlock(); } /* LOCKING @@ -546,20 +546,15 @@ static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv return false; lxc_monitord_spawn(c->config_path); - if (process_lock()) - return false; pid_t pid = fork(); if (pid < 0) { lxc_container_put(c); - process_unlock(); return false; } - if (pid != 0) { - ret = wait_on_daemonized_start(c); - process_unlock(); - return ret; - } - process_unlock(); + if (pid != 0) + return wait_on_daemonized_start(c); + + process_unlock(); // we're no longer sharing /* second fork to be reparented by init */ pid = fork(); if (pid < 0) { @@ -778,6 +773,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet int ret, len, nargs = 0; char **newargv; + process_unlock(); // we're no longer sharing if (quiet) { close(0); close(1); @@ -880,56 +876,44 @@ bool prepend_lxc_header(char *path, const char *t, char *const argv[]) long flen; char *contents; FILE *f; + int ret = -1; #if HAVE_LIBGNUTLS - int i, ret; + int i; unsigned char md_value[SHA_DIGEST_LENGTH]; char *tpath; bool have_tpath = false; #endif - if ((f = fopen(path, "r")) == NULL) { - SYSERROR("Opening old config"); - return false; - } - if (fseek(f, 0, SEEK_END) < 0) { - SYSERROR("Seeking to end of old config file"); - fclose(f); - return false; - } - if ((flen = ftell(f)) < 0) { - SYSERROR("telling size of old config"); - fclose(f); - return false; - } - if (fseek(f, 0, SEEK_SET) < 0) { - SYSERROR("rewinding old config"); - fclose(f); - return false; - } - if ((contents = malloc(flen + 1)) == NULL) { - SYSERROR("out of memory"); - fclose(f); - return false; - } - if (fread(contents, 1, flen, f) != flen) { - SYSERROR("Reading old config"); - free(contents); - fclose(f); + process_lock(); + f = fopen(path, "r"); + process_unlock(); + if (f == NULL) return false; - } + + if (fseek(f, 0, SEEK_END) < 0) + goto out_error; + if ((flen = ftell(f)) < 0) + goto out_error; + if (fseek(f, 0, SEEK_SET) < 0) + goto out_error; + if ((contents = malloc(flen + 1)) == NULL) + goto out_error; + if (fread(contents, 1, flen, f) != flen) + goto out_free_contents; + contents[flen] = '\0'; - if (fclose(f) < 0) { - SYSERROR("closing old config"); - free(contents); - return false; - } + process_lock(); + ret = fclose(f); + process_unlock(); + f = NULL; + if (ret < 0) + goto out_free_contents; #if HAVE_LIBGNUTLS tpath = get_template_path(t); if (tpath == (char *) -1) { ERROR("bad template: %s\n", t); - free(contents); - return false; + goto out_free_contents; } if (tpath) { @@ -937,14 +921,16 @@ bool prepend_lxc_header(char *path, const char *t, char *const argv[]) ret = sha1sum_file(tpath, md_value); if (ret < 0) { ERROR("Error getting sha1sum of %s", tpath); - free(contents); - return false; + goto out_free_contents; } free(tpath); } #endif - if ((f = fopen(path, "w")) == NULL) { + process_lock(); + f = fopen(path, "w"); + process_unlock(); + if (f == NULL) { SYSERROR("reopening config for writing"); free(contents); return false; @@ -969,12 +955,25 @@ bool prepend_lxc_header(char *path, const char *t, char *const argv[]) if (fwrite(contents, 1, flen, f) != flen) { SYSERROR("Writing original contents"); free(contents); + process_lock(); fclose(f); + process_unlock(); return false; } + ret = 0; +out_free_contents: free(contents); - if (fclose(f) < 0) { - SYSERROR("Closing config file after write"); +out_error: + if (f) { + int newret; + process_lock(); + newret = fclose(f); + process_unlock(); + if (ret == 0) + ret = newret; + } + if (ret < 0) { + SYSERROR("Error prepending header"); return false; } return true; @@ -1044,6 +1043,7 @@ static bool lxcapi_create(struct lxc_container *c, const char *t, if (pid == 0) { // child struct bdev *bdev = NULL; + process_unlock(); // we're no longer sharing if (!(bdev = do_bdev_create(c, bdevtype, specs))) { ERROR("Error creating backing store type %s for %s", bdevtype ? bdevtype : "(none)", c->name); @@ -1194,7 +1194,9 @@ char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, in goto out; /* Save reference to old netns */ + process_lock(); old_netns = open("/proc/self/ns/net", O_RDONLY); + process_unlock(); if (old_netns < 0) { SYSERROR("failed to open /proc/self/ns/net"); goto out; @@ -1205,7 +1207,9 @@ char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, in if (ret < 0 || ret >= MAXPATHLEN) goto out; + process_lock(); new_netns = open(new_netns_path, O_RDONLY); + process_unlock(); if (new_netns < 0) { SYSERROR("failed to open %s", new_netns_path); goto out; @@ -1268,10 +1272,12 @@ out: /* Switch back to original netns */ if (old_netns >= 0 && setns(old_netns, CLONE_NEWNET)) SYSERROR("failed to setns"); + process_lock(); if (new_netns >= 0) close(new_netns); if (old_netns >= 0) close(old_netns); + process_unlock(); /* Append NULL to the array */ if (count) { @@ -1390,25 +1396,36 @@ static bool mod_rdep(struct lxc_container *c, bool inc) c->name); if (ret < 0 || ret > MAXPATHLEN) goto out; + process_lock(); f = fopen(path, "r"); + process_unlock(); if (f) { ret = fscanf(f, "%d", &v); + process_lock(); fclose(f); + process_unlock(); if (ret != 1) { ERROR("Corrupted file %s", path); goto out; } } v += inc ? 1 : -1; + process_lock(); f = fopen(path, "w"); + process_unlock(); if (!f) goto out; if (fprintf(f, "%d\n", v) < 0) { ERROR("Error writing new snapshots value"); + process_lock(); fclose(f); + process_unlock(); goto out; } - if (fclose(f) != 0) { + process_lock(); + ret = fclose(f); + process_unlock(); + if (ret != 0) { SYSERROR("Error writing to or closing snapshots file"); goto out; } @@ -1443,7 +1460,10 @@ static void mod_all_rdeps(struct lxc_container *c, bool inc) ERROR("Path name too long"); return; } - if ((f = fopen(path, "r")) == NULL) + process_lock(); + f = fopen(path, "r"); + process_unlock(); + if (f == NULL) return; while (getline(&lxcpath, &pathlen, f) != -1) { if (getline(&lxcname, &namelen, f) == -1) { @@ -1465,7 +1485,9 @@ static void mod_all_rdeps(struct lxc_container *c, bool inc) out: if (lxcpath) free(lxcpath); if (lxcname) free(lxcname); + process_lock(); fclose(f); + process_unlock(); } static bool has_snapshots(struct lxc_container *c) @@ -1479,11 +1501,15 @@ static bool has_snapshots(struct lxc_container *c) c->name); if (ret < 0 || ret > MAXPATHLEN) goto out; + process_lock(); f = fopen(path, "r"); + process_unlock(); if (!f) goto out; ret = fscanf(f, "%d", &v); + process_lock(); fclose(f); + process_unlock(); if (ret != 1) goto out; bret = v != 0; @@ -1735,15 +1761,21 @@ static int copy_file(char *old, char *new) return -1; } + process_lock(); in = open(old, O_RDONLY); + process_unlock(); if (in < 0) { SYSERROR("Error opening original file %s", old); return -1; } + process_lock(); out = open(new, O_CREAT | O_EXCL | O_WRONLY, 0644); + process_unlock(); if (out < 0) { SYSERROR("Error opening new file %s", new); + process_lock(); close(in); + process_unlock(); return -1; } @@ -1761,8 +1793,10 @@ static int copy_file(char *old, char *new) goto err; } } + process_lock(); close(in); close(out); + process_unlock(); // we set mode, but not owner/group ret = chmod(new, sbuf.st_mode); @@ -1774,8 +1808,10 @@ static int copy_file(char *old, char *new) return 0; err: + process_lock(); close(in); close(out); + process_unlock(); return -1; } @@ -1815,13 +1851,18 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c) static void new_hwaddr(char *hwaddr) { - FILE *f = fopen("/dev/urandom", "r"); + FILE *f; + process_lock(); + f = fopen("/dev/urandom", "r"); + process_unlock(); if (f) { unsigned int seed; int ret = fread(&seed, sizeof(seed), 1, f); if (ret != 1) seed = time(NULL); + process_lock(); fclose(f); + process_unlock(); srand(seed); } else srand(time(NULL)); @@ -1911,15 +1952,19 @@ static bool add_rdepends(struct lxc_container *c, struct lxc_container *c0) c->name); if (ret < 0 || ret >= MAXPATHLEN) return false; + process_lock(); f = fopen(path, "a"); + process_unlock(); if (!f) return false; bret = true; // if anything goes wrong, just return an error if (fprintf(f, "%s\n%s\n", c0->config_path, c0->name) < 0) bret = false; + process_lock(); if (fclose(f) != 0) bret = false; + process_unlock(); return bret; } @@ -1976,6 +2021,7 @@ static int clone_update_rootfs(struct lxc_container *c0, if (pid > 0) return wait_for_pid(pid); + process_unlock(); // we're no longer sharing if (unshare(CLONE_NEWNS) < 0) { ERROR("error unsharing mounts"); exit(1); @@ -2097,13 +2143,17 @@ struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *newname, } // copy the configuration, tweak it as needed, + process_lock(); fout = fopen(newpath, "w"); + process_unlock(); if (!fout) { SYSERROR("open %s", newpath); goto out; } write_config(fout, c->lxc_conf); + process_lock(); fclose(fout); + process_unlock(); sprintf(newpath, "%s/%s/rootfs", l, n); if (mkdir(newpath, 0755) < 0) { @@ -2250,6 +2300,7 @@ static int lxcapi_snapshot(struct lxc_container *c, char *commentfile) time_t timer; char buffer[25]; struct tm* tm_info; + FILE *f; time(&timer); tm_info = localtime(&timer); @@ -2258,7 +2309,9 @@ static int lxcapi_snapshot(struct lxc_container *c, char *commentfile) char *dfnam = alloca(strlen(snappath) + strlen(newname) + 5); sprintf(dfnam, "%s/%s/ts", snappath, newname); - FILE *f = fopen(dfnam, "w"); + process_lock(); + f = fopen(dfnam, "w"); + process_unlock(); if (!f) { ERROR("Failed to open %s\n", dfnam); return -1; @@ -2268,7 +2321,10 @@ static int lxcapi_snapshot(struct lxc_container *c, char *commentfile) fclose(f); return -1; } - if (fclose(f) != 0) { + process_lock(); + ret = fclose(f); + process_unlock(); + if (ret != 0) { SYSERROR("Writing timestamp"); return -1; } @@ -2321,7 +2377,10 @@ static char *get_timestamp(char* snappath, char *name) ret = snprintf(path, MAXPATHLEN, "%s/%s/ts", snappath, name); if (ret < 0 || ret >= MAXPATHLEN) return NULL; - if ((fin = fopen(path, "r")) == NULL) + process_lock(); + fin = fopen(path, "r"); + process_unlock(); + if (!fin) return NULL; (void) fseek(fin, 0, SEEK_END); len = ftell(fin); @@ -2337,7 +2396,9 @@ static char *get_timestamp(char* snappath, char *name) } } } + process_lock(); fclose(fin); + process_unlock(); return s; } @@ -2357,7 +2418,10 @@ static int lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **r ERROR("path name too long"); return -1; } - if (!(dir = opendir(snappath))) { + process_lock(); + dir = opendir(snappath); + process_unlock(); + if (!dir) { INFO("failed to open %s - assuming no snapshots", snappath); return 0; } @@ -2399,8 +2463,10 @@ static int lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **r count++; } + process_lock(); if (closedir(dir)) WARN("failed to close directory"); + process_unlock(); *ret_snaps = snaps; return count; diff --git a/src/lxc/lxclock.c b/src/lxc/lxclock.c index 1d6a86c61..1733fd1c6 100644 --- a/src/lxc/lxclock.c +++ b/src/lxc/lxclock.c @@ -271,13 +271,14 @@ void lxc_putlock(struct lxc_lock *l) free(l); } -int process_lock(void) +void process_lock(void) { int ret; - ret = pthread_mutex_lock(&thread_mutex); - if (ret != 0) + + if ((ret = pthread_mutex_lock(&thread_mutex)) != 0) { ERROR("pthread_mutex_lock returned:%d %s", ret, strerror(ret)); - return ret; + exit(1); + } } void process_unlock(void) diff --git a/src/lxc/lxclock.h b/src/lxc/lxclock.h index fae7e4d97..dcdf79d2d 100644 --- a/src/lxc/lxclock.h +++ b/src/lxc/lxclock.h @@ -85,7 +85,7 @@ extern int lxcunlock(struct lxc_lock *lock); extern void lxc_putlock(struct lxc_lock *l); -extern int process_lock(void); +extern void process_lock(void); extern void process_unlock(void); struct lxc_container; extern int container_mem_lock(struct lxc_container *c); diff --git a/src/lxc/lxcutmp.c b/src/lxc/lxcutmp.c index 8736f3fa0..bfebe55f3 100644 --- a/src/lxc/lxcutmp.c +++ b/src/lxc/lxcutmp.c @@ -62,6 +62,7 @@ static int timerfd_settime (int __ufd, int __flags, #include "mainloop.h" #include "lxc.h" #include "log.h" +#include "lxclock.h" #ifndef __USE_GNU #define __USE_GNU @@ -342,7 +343,9 @@ run_ok: memset(utmp_data, 0, sizeof(struct lxc_utmp)); + process_lock(); fd = inotify_init(); + process_unlock(); if (fd < 0) { SYSERROR("failed to inotify_init"); goto out; @@ -376,7 +379,9 @@ run_ok: return 0; out_close: + process_lock(); close(fd); + process_unlock(); out: free(utmp_data); return -1; @@ -426,7 +431,9 @@ int lxc_utmp_add_timer(struct lxc_epoll_descr *descr, struct itimerspec timeout; struct lxc_utmp *utmp_data = (struct lxc_utmp *)data; + process_lock(); fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + process_unlock(); if (fd < 0) { SYSERROR("failed to create timer"); return -1; @@ -450,7 +457,9 @@ int lxc_utmp_add_timer(struct lxc_epoll_descr *descr, if (lxc_mainloop_add_handler(descr, fd, callback, utmp_data)) { SYSERROR("failed to add utmp timer to mainloop"); + process_lock(); close(fd); + process_unlock(); return -1; } @@ -471,7 +480,9 @@ int lxc_utmp_del_timer(struct lxc_epoll_descr *descr, SYSERROR("failed to del utmp timer from mainloop"); /* shutdown timer_fd */ + process_lock(); close(utmp_data->timer_fd); + process_unlock(); utmp_data->timer_fd = -1; if (result < 0) diff --git a/src/lxc/mainloop.c b/src/lxc/mainloop.c index 2ac49964b..9ba98ee0d 100644 --- a/src/lxc/mainloop.c +++ b/src/lxc/mainloop.c @@ -29,6 +29,7 @@ #include #include "mainloop.h" +#include "lxclock.h" struct mainloop_handler { lxc_mainloop_callback_t callback; @@ -132,12 +133,16 @@ int lxc_mainloop_del_handler(struct lxc_epoll_descr *descr, int fd) int lxc_mainloop_open(struct lxc_epoll_descr *descr) { /* hint value passed to epoll create */ + process_lock(); descr->epfd = epoll_create(2); + process_unlock(); if (descr->epfd < 0) return -1; if (fcntl(descr->epfd, F_SETFD, FD_CLOEXEC)) { + process_lock(); close(descr->epfd); + process_unlock(); return -1; } @@ -148,6 +153,7 @@ int lxc_mainloop_open(struct lxc_epoll_descr *descr) int lxc_mainloop_close(struct lxc_epoll_descr *descr) { struct lxc_list *iterator, *next; + int ret; iterator = descr->handlers.next; while (iterator != &descr->handlers) { @@ -159,6 +165,9 @@ int lxc_mainloop_close(struct lxc_epoll_descr *descr) iterator = next; } - return close(descr->epfd); + process_lock(); + ret = close(descr->epfd); + process_unlock(); + return ret; } diff --git a/src/lxc/monitor.c b/src/lxc/monitor.c index 64e9987fc..e736937c4 100644 --- a/src/lxc/monitor.c +++ b/src/lxc/monitor.c @@ -90,7 +90,9 @@ static void lxc_monitor_fifo_send(struct lxc_msg *msg, const char *lxcpath) if (ret < 0) return; + process_lock(); fd = open(fifo_path, O_WRONLY); + process_unlock(); if (fd < 0) { /* it is normal for this open to fail when there is no monitor * running, so we don't log it @@ -100,12 +102,16 @@ static void lxc_monitor_fifo_send(struct lxc_msg *msg, const char *lxcpath) ret = write(fd, msg, sizeof(*msg)); if (ret != sizeof(*msg)) { + process_lock(); close(fd); + process_unlock(); SYSERROR("failed to write monitor fifo %s", fifo_path); return; } + process_lock(); close(fd); + process_unlock(); } void lxc_monitor_send_state(const char *name, lxc_state_t state, const char *lxcpath) @@ -122,7 +128,12 @@ void lxc_monitor_send_state(const char *name, lxc_state_t state, const char *lxc /* routines used by monitor subscribers (lxc-monitor) */ int lxc_monitor_close(int fd) { - return close(fd); + int ret; + + process_lock(); + ret = close(fd); + process_unlock(); + return ret; } /* Note we don't use SHA-1 here as we don't want to depend on HAVE_GNUTLS. @@ -187,7 +198,9 @@ int lxc_monitor_open(const char *lxcpath) if (lxc_monitor_sock_name(lxcpath, &addr) < 0) return -1; + process_lock(); fd = socket(PF_UNIX, SOCK_STREAM, 0); + process_unlock(); if (fd < 0) { ERROR("socket : %s", strerror(errno)); return -1; @@ -207,7 +220,9 @@ int lxc_monitor_open(const char *lxcpath) } return fd; err1: + process_lock(); close(fd); + process_unlock(); return ret; } @@ -293,6 +308,7 @@ int lxc_monitord_spawn(const char *lxcpath) return 0; } + process_unlock(); // we're no longer sharing if (pipe(pipefd) < 0) { SYSERROR("failed to create pipe"); exit(EXIT_FAILURE); diff --git a/src/lxc/network.c b/src/lxc/network.c index f7c9ce4ce..1be231d3b 100644 --- a/src/lxc/network.c +++ b/src/lxc/network.c @@ -48,6 +48,7 @@ #include "nl.h" #include "network.h" #include "conf.h" +#include "lxclock.h" #ifndef IFLA_LINKMODE # define IFLA_LINKMODE 17 @@ -569,14 +570,18 @@ static int proc_sys_net_write(const char *path, const char *value) { int fd, err = 0; + process_lock(); fd = open(path, O_WRONLY); + process_unlock(); if (fd < 0) return -errno; if (write(fd, value, strlen(value)) < 0) err = -errno; + process_lock(); close(fd); + process_unlock(); return err; } @@ -994,14 +999,18 @@ int lxc_bridge_attach(const char *bridge, const char *ifname) if (!index) return -EINVAL; + process_lock(); fd = socket(AF_INET, SOCK_STREAM, 0); + process_unlock(); if (fd < 0) return -errno; strncpy(ifr.ifr_name, bridge, IFNAMSIZ); ifr.ifr_ifindex = index; err = ioctl(fd, SIOCBRADDIF, &ifr); + process_lock(); close(fd); + process_unlock(); if (err) err = -errno; diff --git a/src/lxc/nl.c b/src/lxc/nl.c index 7c0f1e53b..615316167 100644 --- a/src/lxc/nl.c +++ b/src/lxc/nl.c @@ -31,6 +31,7 @@ #include #include "nl.h" +#include "lxclock.h" #define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) @@ -222,7 +223,9 @@ extern int netlink_open(struct nl_handler *handler, int protocol) memset(handler, 0, sizeof(*handler)); + process_lock(); handler->fd = socket(AF_NETLINK, SOCK_RAW, protocol); + process_unlock(); if (handler->fd < 0) return -errno; @@ -260,7 +263,9 @@ extern int netlink_open(struct nl_handler *handler, int protocol) extern int netlink_close(struct nl_handler *handler) { + process_lock(); close(handler->fd); + process_unlock(); handler->fd = -1; return 0; } diff --git a/src/lxc/parse.c b/src/lxc/parse.c index 26cbbdd00..7875c8969 100644 --- a/src/lxc/parse.c +++ b/src/lxc/parse.c @@ -31,6 +31,7 @@ #include "parse.h" #include "config.h" #include "utils.h" +#include "lxclock.h" #include /* Workaround for the broken signature of alphasort() in bionic. @@ -90,7 +91,9 @@ int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data) char *line = NULL; size_t len = 0; + process_lock(); f = fopen(file, "r"); + process_unlock(); if (!f) { SYSERROR("failed to open %s", file); return -1; @@ -104,7 +107,9 @@ int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data) if (line) free(line); + process_lock(); fclose(f); + process_unlock(); return err; } diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c index 1abd69711..9246f2d7d 100644 --- a/src/lxc/seccomp.c +++ b/src/lxc/seccomp.c @@ -29,6 +29,7 @@ #include #include "config.h" #include "lxcseccomp.h" +#include "lxclock.h" #include "log.h" @@ -114,13 +115,17 @@ int lxc_read_seccomp_config(struct lxc_conf *conf) return -1; } + process_lock(); f = fopen(conf->seccomp, "r"); + process_unlock(); if (!f) { SYSERROR("failed to open seccomp policy file %s\n", conf->seccomp); return -1; } ret = parse_config(f, conf); + process_lock(); fclose(f); + process_unlock(); return ret; } diff --git a/src/lxc/start.c b/src/lxc/start.c index 48a06cfa8..c968bb134 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -71,6 +71,7 @@ #include "apparmor.h" #include "lxcseccomp.h" #include "caps.h" +#include "lxclock.h" lxc_log_define(lxc_start, lxc); @@ -86,7 +87,9 @@ int lxc_check_inherited(struct lxc_conf *conf, int fd_to_ignore) DIR *dir; restart: + process_lock(); dir = opendir("/proc/self/fd"); + process_unlock(); if (!dir) { WARN("failed to open directory: %m"); return -1; @@ -113,15 +116,19 @@ restart: continue; if (conf->close_all_fds) { + process_lock(); close(fd); closedir(dir); + process_unlock(); INFO("closed inherited fd %d", fd); goto restart; } WARN("inherited fd %d", fd); } + process_lock(); closedir(dir); /* cannot fail */ + process_unlock(); return 0; } @@ -258,7 +265,9 @@ int lxc_poll(const char *name, struct lxc_handler *handler) out_mainloop_open: lxc_mainloop_close(&descr); out_sigfd: + process_lock(); close(sigfd); + process_unlock(); return -1; } @@ -353,7 +362,9 @@ out_delete_tty: out_aborting: lxc_set_state(name, handler, ABORTING); out_close_maincmd_fd: + process_lock(); close(conf->maincmd_fd); + process_unlock(); conf->maincmd_fd = -1; out_free_name: free(handler->name); @@ -380,7 +391,9 @@ static void lxc_fini(const char *name, struct lxc_handler *handler) lxc_console_delete(&handler->conf->console); lxc_delete_tty(&handler->conf->tty_info); + process_lock(); close(handler->conf->maincmd_fd); + process_unlock(); handler->conf->maincmd_fd = -1; free(handler->name); if (handler->cgroup) { @@ -421,20 +434,25 @@ static int container_reboot_supported(void *arg) static int must_drop_cap_sys_boot(struct lxc_conf *conf) { - FILE *f = fopen("/proc/sys/kernel/ctrl-alt-del", "r"); + FILE *f; int ret, cmd, v, flags; long stack_size = 4096; void *stack = alloca(stack_size); int status; pid_t pid; + process_lock(); + f = fopen("/proc/sys/kernel/ctrl-alt-del", "r"); + process_unlock(); if (!f) { DEBUG("failed to open /proc/sys/kernel/ctrl-alt-del"); return 1; } ret = fscanf(f, "%d", &v); + process_lock(); fclose(f); + process_unlock(); if (ret != 1) { DEBUG("Failed to read /proc/sys/kernel/ctrl-alt-del"); return 1; @@ -489,8 +507,11 @@ static int do_start(void *data) lxc_sync_fini_parent(handler); /* don't leak the pinfd to the container */ - if (handler->pinfd >= 0) + if (handler->pinfd >= 0) { + process_lock(); close(handler->pinfd); + process_unlock(); + } /* Tell the parent task it can begin to configure the * container and wait for it to finish @@ -560,7 +581,9 @@ static int do_start(void *data) goto out_warn_father; } + process_lock(); close(handler->sigfd); + process_unlock(); /* after this call, we are in error because this * ops should not return as it execs */ @@ -780,7 +803,9 @@ out_abort: lxc_abort(name, handler); lxc_sync_fini(handler); if (handler->pinfd >= 0) { + process_lock(); close(handler->pinfd); + process_unlock(); handler->pinfd = -1; } @@ -852,7 +877,9 @@ int __lxc_start(const char *name, struct lxc_conf *conf, lxc_rename_phys_nics_on_shutdown(handler->conf); if (handler->pinfd >= 0) { + process_lock(); close(handler->pinfd); + process_unlock(); handler->pinfd = -1; } diff --git a/src/lxc/state.c b/src/lxc/state.c index 398833aa9..92be56053 100644 --- a/src/lxc/state.c +++ b/src/lxc/state.c @@ -39,6 +39,7 @@ #include #include "commands.h" #include "config.h" +#include "lxclock.h" lxc_log_define(lxc_state, lxc); @@ -83,14 +84,18 @@ static lxc_state_t freezer_state(const char *name, const char *lxcpath) if (ret < 0 || ret >= MAXPATHLEN) goto out; + process_lock(); file = fopen(freezer, "r"); + process_unlock(); if (!file) { ret = -1; goto out; } ret = fscanf(file, "%s", status); + process_lock(); fclose(file); + process_unlock(); if (ret == EOF) { SYSERROR("failed to read %s", freezer); diff --git a/src/lxc/sync.c b/src/lxc/sync.c index 4df2b5fad..a3b4a1af3 100644 --- a/src/lxc/sync.c +++ b/src/lxc/sync.c @@ -29,6 +29,7 @@ #include "log.h" #include "start.h" +#include "lxclock.h" lxc_log_define(lxc_sync, lxc); @@ -99,7 +100,12 @@ int lxc_sync_wake_child(struct lxc_handler *handler, int sequence) int lxc_sync_init(struct lxc_handler *handler) { - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, handler->sv)) { + int ret; + + process_lock(); + ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, handler->sv); + process_unlock(); + if (ret) { SYSERROR("failed to create synchronization socketpair"); return -1; } @@ -113,7 +119,9 @@ int lxc_sync_init(struct lxc_handler *handler) void lxc_sync_fini_child(struct lxc_handler *handler) { if (handler->sv[0] != -1) { + process_lock(); close(handler->sv[0]); + process_unlock(); handler->sv[0] = -1; } } @@ -121,7 +129,9 @@ void lxc_sync_fini_child(struct lxc_handler *handler) void lxc_sync_fini_parent(struct lxc_handler *handler) { if (handler->sv[1] != -1) { + process_lock(); close(handler->sv[1]); + process_unlock(); handler->sv[1] = -1; } } diff --git a/src/lxc/utils.c b/src/lxc/utils.c index 78b234d98..00e13d595 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -47,6 +47,7 @@ #include "utils.h" #include "log.h" +#include "lxclock.h" lxc_log_define(lxc_utils, lxc); @@ -57,7 +58,9 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev) int ret, failed=0; char pathname[MAXPATHLEN]; + process_lock(); dir = opendir(dirname); + process_unlock(); if (!dir) { ERROR("%s: failed to open %s", __func__, dirname); return 0; @@ -104,7 +107,10 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev) failed=1; } - if (closedir(dir)) { + process_lock(); + ret = closedir(dir); + process_unlock(); + if (ret) { ERROR("%s: failed to close directory %s", __func__, dirname); failed=1; } @@ -253,7 +259,9 @@ const char *lxc_global_config_value(const char *option_name) if (values[i]) return values[i]; + process_lock(); fin = fopen_cloexec(LXC_GLOBAL_CONF, "r"); + process_unlock(); if (fin) { while (fgets(buf, 1024, fin)) { if (buf[0] == '#') @@ -299,8 +307,10 @@ const char *lxc_global_config_value(const char *option_name) errno = 0; out: + process_lock(); if (fin) fclose(fin); + process_unlock(); return values[i]; } @@ -397,6 +407,15 @@ ssize_t lxc_read_nointr_expect(int fd, void* buf, size_t count, const void* expe return ret; } +static inline int lock_fclose(FILE *f) +{ + int ret; + process_lock(); + ret = fclose(f); + process_unlock(); + return ret; +} + #if HAVE_LIBGNUTLS #include #include @@ -409,37 +428,40 @@ int sha1sum_file(char *fnam, unsigned char *digest) if (!fnam) return -1; - if ((f = fopen_cloexec(fnam, "r")) < 0) { + process_lock(); + f = fopen_cloexec(fnam, "r"); + process_unlock(); + if (f < 0) { SYSERROR("Error opening template"); return -1; } if (fseek(f, 0, SEEK_END) < 0) { SYSERROR("Error seeking to end of template"); - fclose(f); + lock_fclose(f); return -1; } if ((flen = ftell(f)) < 0) { SYSERROR("Error telling size of template"); - fclose(f); + lock_fclose(f); return -1; } if (fseek(f, 0, SEEK_SET) < 0) { SYSERROR("Error seeking to start of template"); - fclose(f); + lock_fclose(f); return -1; } if ((buf = malloc(flen+1)) == NULL) { SYSERROR("Out of memory"); - fclose(f); + lock_fclose(f); return -1; } if (fread(buf, 1, flen, f) != flen) { SYSERROR("Failure reading template"); free(buf); - fclose(f); + lock_fclose(f); return -1; } - if (fclose(f) < 0) { + if (lock_fclose(f) < 0) { SYSERROR("Failre closing template"); free(buf); return -1; @@ -496,6 +518,10 @@ const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip) return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0); } +/* + * fopen_cloexec: must be called with process_lock() held + * if it is needed. + */ FILE *fopen_cloexec(const char *path, const char *mode) { int open_mode = 0; @@ -847,7 +873,9 @@ int lxc_write_to_file(const char *filename, const void* buf, size_t count, bool int fd, saved_errno; ssize_t ret; + process_lock(); fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666); + process_unlock(); if (fd < 0) return -1; ret = lxc_write_nointr(fd, buf, count); @@ -860,12 +888,16 @@ int lxc_write_to_file(const char *filename, const void* buf, size_t count, bool if (ret != 1) goto out_error; } + process_lock(); close(fd); + process_unlock(); return 0; out_error: saved_errno = errno; + process_lock(); close(fd); + process_unlock(); errno = saved_errno; return -1; } @@ -875,7 +907,9 @@ int lxc_read_from_file(const char *filename, void* buf, size_t count) int fd = -1, saved_errno; ssize_t ret; + process_lock(); fd = open(filename, O_RDONLY | O_CLOEXEC); + process_unlock(); if (fd < 0) return -1; @@ -895,7 +929,9 @@ int lxc_read_from_file(const char *filename, void* buf, size_t count) ERROR("read %s: %s", filename, strerror(errno)); saved_errno = errno; + process_lock(); close(fd); + process_unlock(); errno = saved_errno; return ret; }