2 * Metadata on-disk locking for processes serialization
4 * Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2016-2021 Ondrej Kozina
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <linux/limits.h>
29 #include <sys/types.h>
31 #ifdef HAVE_SYS_SYSMACROS_H
32 # include <sys/sysmacros.h> /* for major, minor */
38 #include "utils_device_locking.h"
40 #define same_inode(buf1, buf2) \
41 ((buf1).st_ino == (buf2).st_ino && \
42 (buf1).st_dev == (buf2).st_dev)
55 struct crypt_lock_handle {
70 static int resource_by_name(char *res, size_t res_size, const char *name, bool fullpath)
75 r = snprintf(res, res_size, "%s/LN_%s", DEFAULT_LUKS2_LOCK_PATH, name);
77 r = snprintf(res, res_size, "LN_%s", name);
79 return (r < 0 || (size_t)r >= res_size) ? -EINVAL : 0;
82 static int resource_by_devno(char *res, size_t res_size, dev_t devno, unsigned fullpath)
87 r = snprintf(res, res_size, "%s/L_%d:%d", DEFAULT_LUKS2_LOCK_PATH, major(devno), minor(devno));
89 r = snprintf(res, res_size, "L_%d:%d", major(devno), minor(devno));
91 return (r < 0 || (size_t)r >= res_size) ? -EINVAL : 0;
94 static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *base)
98 dirfd = open(dir, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
100 log_dbg(cd, "Failed to open directory %s: (%d: %s).", dir, errno, strerror(errno));
101 if (errno == ENOTDIR || errno == ENOENT)
102 log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (not a directory or missing)."), dir, base);
106 lockdfd = openat(dirfd, base, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
108 if (errno == ENOENT) {
109 log_dbg(cd, _("Locking directory %s/%s will be created with default compiled-in permissions."), dir, base);
111 /* success or failure w/ errno == EEXIST either way just try to open the 'base' directory again */
112 if (mkdirat(dirfd, base, DEFAULT_LUKS2_LOCK_DIR_PERMS) && errno != EEXIST)
113 log_dbg(cd, "Failed to create directory %s in %s (%d: %s).", base, dir, errno, strerror(errno));
115 lockdfd = openat(dirfd, base, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
117 log_dbg(cd, "Failed to open directory %s/%s: (%d: %s)", dir, base, errno, strerror(errno));
118 if (errno == ENOTDIR || errno == ELOOP)
119 log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (%s is not a directory)."), dir, base, base);
124 return lockdfd >= 0 ? lockdfd : -EINVAL;
127 static int open_resource(struct crypt_device *cd, const char *res)
129 int err, lockdir_fd, r;
130 char dir[] = DEFAULT_LUKS2_LOCK_PATH,
131 base[] = DEFAULT_LUKS2_LOCK_PATH;
133 lockdir_fd = open_lock_dir(cd, dirname(dir), basename(base));
137 log_dbg(cd, "Opening lock resource file %s/%s", DEFAULT_LUKS2_LOCK_PATH, res);
138 r = openat(lockdir_fd, res, O_CREAT | O_NOFOLLOW | O_RDWR | O_CLOEXEC, 0777);
143 return r < 0 ? -err : r;
146 static int acquire_lock_handle(struct crypt_device *cd, struct device *device, struct crypt_lock_handle *h)
152 dev_fd = open(device_path(device), O_RDONLY | O_NONBLOCK | O_CLOEXEC);
156 if (fstat(dev_fd, &st)) {
161 if (S_ISBLK(st.st_mode)) {
162 if (resource_by_devno(res, sizeof(res), st.st_rdev, 0)) {
167 fd = open_resource(cd, res);
173 h->u.bdev.devno = st.st_rdev;
174 h->mode = DEV_LOCK_BDEV;
175 } else if (S_ISREG(st.st_mode)) {
176 // FIXME: workaround for nfsv4
177 fd = open(device_path(device), O_RDWR | O_NONBLOCK | O_CLOEXEC);
179 h->flock_fd = dev_fd;
184 h->mode = DEV_LOCK_FILE;
186 /* Wrong device type */
194 static int acquire_lock_handle_by_name(struct crypt_device *cd, const char *name, struct crypt_lock_handle *h)
199 h->u.name.name = strdup(name);
203 if (resource_by_name(res, sizeof(res), name, false)) {
204 free(h->u.name.name);
208 fd = open_resource(cd, res);
210 free(h->u.name.name);
215 h->mode = DEV_LOCK_NAME;
220 static void release_lock_handle(struct crypt_device *cd, struct crypt_lock_handle *h)
223 struct stat buf_a, buf_b;
225 if ((h->mode == DEV_LOCK_NAME) && /* was it name lock */
226 !flock(h->flock_fd, LOCK_EX | LOCK_NB) && /* lock to drop the file */
227 !resource_by_name(res, sizeof(res), h->u.name.name, true) && /* acquire lock resource name */
228 !fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
229 !stat(res, &buf_b) && /* does path file still exist? */
230 same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
231 /* coverity[toctou] */
232 if (unlink(res)) /* yes? unlink the file */
233 log_dbg(cd, "Failed to unlink resource file: %s", res);
236 if ((h->mode == DEV_LOCK_BDEV) && /* was it block device */
237 !flock(h->flock_fd, LOCK_EX | LOCK_NB) && /* lock to drop the file */
238 !resource_by_devno(res, sizeof(res), h->u.bdev.devno, 1) && /* acquire lock resource name */
239 !fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
240 !stat(res, &buf_b) && /* does path file still exist? */
241 same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
242 /* coverity[toctou] */
243 if (unlink(res)) /* yes? unlink the file */
244 log_dbg(cd, "Failed to unlink resource file: %s", res);
247 if (h->mode == DEV_LOCK_NAME)
248 free(h->u.name.name);
250 if (close(h->flock_fd))
251 log_dbg(cd, "Failed to close lock resource fd (%d).", h->flock_fd);
254 int device_locked(struct crypt_lock_handle *h)
256 return (h && (h->type == DEV_LOCK_READ || h->type == DEV_LOCK_WRITE));
259 int device_locked_readonly(struct crypt_lock_handle *h)
261 return (h && h->type == DEV_LOCK_READ);
264 static int verify_lock_handle(const char *device_path, struct crypt_lock_handle *h)
267 struct stat lck_st, res_st;
269 /* we locked a regular file, check during device_open() instead. No reason to check now */
270 if (h->mode == DEV_LOCK_FILE)
273 if (h->mode == DEV_LOCK_NAME) {
274 if (resource_by_name(res, sizeof(res), h->u.name.name, true))
276 } else if (h->mode == DEV_LOCK_BDEV) {
277 if (resource_by_devno(res, sizeof(res), h->u.bdev.devno, true))
282 if (fstat(h->flock_fd, &lck_st))
285 return (stat(res, &res_st) || !same_inode(lck_st, res_st)) ? -EAGAIN : 0;
288 static unsigned device_lock_inc(struct crypt_lock_handle *h)
293 static unsigned device_lock_dec(struct crypt_lock_handle *h)
300 static int acquire_and_verify(struct crypt_device *cd, struct device *device, const char *resource, int flock_op, struct crypt_lock_handle **lock)
303 struct crypt_lock_handle *h;
305 if (device && resource)
308 if (!(h = malloc(sizeof(*h))))
312 r = device ? acquire_lock_handle(cd, device, h) : acquire_lock_handle_by_name(cd, resource, h);
316 if (flock(h->flock_fd, flock_op)) {
317 log_dbg(cd, "Flock on fd %d failed with errno %d.", h->flock_fd, errno);
318 r = (errno == EWOULDBLOCK) ? -EBUSY : -EINVAL;
319 release_lock_handle(cd, h);
323 log_dbg(cd, "Verifying lock handle for %s.", device ? device_path(device) : resource);
326 * check whether another libcryptsetup process removed resource file before this
327 * one managed to flock() it. See release_lock_handle() for details
329 r = verify_lock_handle(device_path(device), h);
331 if (flock(h->flock_fd, LOCK_UN))
332 log_dbg(cd, "flock on fd %d failed.", h->flock_fd);
333 release_lock_handle(cd, h);
334 log_dbg(cd, "Lock handle verification failed.");
336 } while (r == -EAGAIN);
348 int device_read_lock_internal(struct crypt_device *cd, struct device *device)
351 struct crypt_lock_handle *h;
356 h = device_get_lock_handle(device);
358 if (device_locked(h)) {
360 log_dbg(cd, "Device %s READ lock (or higher) already held.", device_path(device));
364 log_dbg(cd, "Acquiring read lock for device %s.", device_path(device));
366 r = acquire_and_verify(cd, device, NULL, LOCK_SH, &h);
370 h->type = DEV_LOCK_READ;
372 device_set_lock_handle(device, h);
374 log_dbg(cd, "Device %s READ lock taken.", device_path(device));
379 int device_write_lock_internal(struct crypt_device *cd, struct device *device)
382 struct crypt_lock_handle *h;
387 h = device_get_lock_handle(device);
389 if (device_locked(h)) {
390 log_dbg(cd, "Device %s WRITE lock already held.", device_path(device));
391 return device_lock_inc(h);
394 log_dbg(cd, "Acquiring write lock for device %s.", device_path(device));
396 r = acquire_and_verify(cd, device, NULL, LOCK_EX, &h);
400 h->type = DEV_LOCK_WRITE;
402 device_set_lock_handle(device, h);
404 log_dbg(cd, "Device %s WRITE lock taken.", device_path(device));
409 int crypt_read_lock(struct crypt_device *cd, const char *resource, bool blocking, struct crypt_lock_handle **lock)
412 struct crypt_lock_handle *h;
417 log_dbg(cd, "Acquiring %sblocking read lock for resource %s.", blocking ? "" : "non", resource);
419 r = acquire_and_verify(cd, NULL, resource, LOCK_SH | (blocking ? 0 : LOCK_NB), &h);
423 h->type = DEV_LOCK_READ;
426 log_dbg(cd, "READ lock for resource %s taken.", resource);
433 int crypt_write_lock(struct crypt_device *cd, const char *resource, bool blocking, struct crypt_lock_handle **lock)
436 struct crypt_lock_handle *h;
441 log_dbg(cd, "Acquiring %sblocking write lock for resource %s.", blocking ? "" : "non", resource);
443 r = acquire_and_verify(cd, NULL, resource, LOCK_EX | (blocking ? 0 : LOCK_NB), &h);
447 h->type = DEV_LOCK_WRITE;
450 log_dbg(cd, "WRITE lock for resource %s taken.", resource);
457 static void unlock_internal(struct crypt_device *cd, struct crypt_lock_handle *h)
459 if (flock(h->flock_fd, LOCK_UN))
460 log_dbg(cd, "flock on fd %d failed.", h->flock_fd);
461 release_lock_handle(cd, h);
465 void crypt_unlock_internal(struct crypt_device *cd, struct crypt_lock_handle *h)
470 /* nested locks are illegal */
471 assert(!device_lock_dec(h));
473 log_dbg(cd, "Unlocking %s lock for resource %s.",
474 device_locked_readonly(h) ? "READ" : "WRITE", h->u.name.name);
476 unlock_internal(cd, h);
479 void device_unlock_internal(struct crypt_device *cd, struct device *device)
482 struct crypt_lock_handle *h = device_get_lock_handle(device);
483 unsigned u = device_lock_dec(h);
488 readonly = device_locked_readonly(h);
490 unlock_internal(cd, h);
492 log_dbg(cd, "Device %s %s lock released.", device_path(device),
493 readonly ? "READ" : "WRITE");
495 device_set_lock_handle(device, NULL);
498 int device_locked_verify(struct crypt_device *cd, int dev_fd, struct crypt_lock_handle *h)
501 struct stat dev_st, lck_st, st;
503 if (fstat(dev_fd, &dev_st) || fstat(h->flock_fd, &lck_st))
506 /* if device handle is regular file the handle must match the lock handle */
507 if (S_ISREG(dev_st.st_mode)) {
508 log_dbg(cd, "Veryfing locked device handle (regular file)");
509 if (!same_inode(dev_st, lck_st))
511 } else if (S_ISBLK(dev_st.st_mode)) {
512 log_dbg(cd, "Veryfing locked device handle (bdev)");
513 if (resource_by_devno(res, sizeof(res), dev_st.st_rdev, 1) ||
515 !same_inode(lck_st, st))