Merge branch 'upstream' into tizen
[platform/upstream/cryptsetup.git] / lib / utils_device_locking.c
1 /*
2  * Metadata on-disk locking for processes serialization
3  *
4  * Copyright (C) 2016-2023 Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2016-2023 Ondrej Kozina
6  *
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.
11  *
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.
16  *
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.
20  */
21
22 #include <errno.h>
23 #include <linux/limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/file.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #ifdef HAVE_SYS_SYSMACROS_H
32 # include <sys/sysmacros.h>     /* for major, minor */
33 #endif
34 #include <libgen.h>
35
36 #include "internal.h"
37 #include "utils_device_locking.h"
38
39 #define same_inode(buf1, buf2) \
40         ((buf1).st_ino == (buf2).st_ino && \
41          (buf1).st_dev == (buf2).st_dev)
42
43 enum lock_type {
44         DEV_LOCK_READ = 0,
45         DEV_LOCK_WRITE
46 };
47
48 enum lock_mode {
49         DEV_LOCK_FILE = 0,
50         DEV_LOCK_BDEV,
51         DEV_LOCK_NAME
52 };
53
54 struct crypt_lock_handle {
55         unsigned refcnt;
56         int flock_fd;
57         enum lock_type type;
58         enum lock_mode mode;
59         union {
60         struct {
61                 dev_t devno;
62         } bdev;
63         struct {
64                 char *name;
65         } name;
66         } u;
67 };
68
69 static int resource_by_name(char *res, size_t res_size, const char *name, bool fullpath)
70 {
71         int r;
72
73         if (fullpath)
74                 r = snprintf(res, res_size, "%s/LN_%s", DEFAULT_LUKS2_LOCK_PATH, name);
75         else
76                 r = snprintf(res, res_size, "LN_%s", name);
77
78         return (r < 0 || (size_t)r >= res_size) ? -EINVAL : 0;
79 }
80
81 static int resource_by_devno(char *res, size_t res_size, dev_t devno, unsigned fullpath)
82 {
83         int r;
84
85         if (fullpath)
86                 r = snprintf(res, res_size, "%s/L_%d:%d", DEFAULT_LUKS2_LOCK_PATH, major(devno), minor(devno));
87         else
88                 r = snprintf(res, res_size, "L_%d:%d", major(devno), minor(devno));
89
90         return (r < 0 || (size_t)r >= res_size) ? -EINVAL : 0;
91 }
92
93 static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *base)
94 {
95         int dirfd, lockdfd;
96
97         dirfd = open(dir, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
98         if (dirfd < 0) {
99                 log_dbg(cd, "Failed to open directory %s: (%d: %s).", dir, errno, strerror(errno));
100                 if (errno == ENOTDIR || errno == ENOENT)
101                         log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (not a directory or missing)."), dir, base);
102                 return -EINVAL;
103         }
104
105         lockdfd = openat(dirfd, base, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
106         if (lockdfd < 0) {
107                 if (errno == ENOENT) {
108                         log_dbg(cd, "Locking directory %s/%s will be created with default compiled-in permissions.", dir, base);
109
110                         /* success or failure w/ errno == EEXIST either way just try to open the 'base' directory again */
111                         if (mkdirat(dirfd, base, DEFAULT_LUKS2_LOCK_DIR_PERMS) && errno != EEXIST)
112                                 log_dbg(cd, "Failed to create directory %s in %s (%d: %s).", base, dir, errno, strerror(errno));
113                         else
114                                 lockdfd = openat(dirfd, base, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
115                 } else {
116                         log_dbg(cd, "Failed to open directory %s/%s: (%d: %s)", dir, base, errno, strerror(errno));
117                         if (errno == ENOTDIR || errno == ELOOP)
118                                 log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (%s is not a directory)."), dir, base, base);
119                 }
120         }
121
122         close(dirfd);
123         return lockdfd >= 0 ? lockdfd : -EINVAL;
124 }
125
126 static int open_resource(struct crypt_device *cd, const char *res)
127 {
128         int err, lockdir_fd, r;
129         char dir[] = DEFAULT_LUKS2_LOCK_PATH,
130              base[] = DEFAULT_LUKS2_LOCK_PATH;
131
132         lockdir_fd = open_lock_dir(cd, dirname(dir), basename(base));
133         if (lockdir_fd < 0)
134                 return -EINVAL;
135
136         log_dbg(cd, "Opening lock resource file %s/%s", DEFAULT_LUKS2_LOCK_PATH, res);
137         r = openat(lockdir_fd, res, O_CREAT | O_NOFOLLOW | O_RDWR | O_CLOEXEC, 0777);
138         err = errno;
139
140         close(lockdir_fd);
141
142         return r < 0 ? -err : r;
143 }
144
145 static int acquire_lock_handle(struct crypt_device *cd, struct device *device, struct crypt_lock_handle *h)
146 {
147         char res[PATH_MAX];
148         int dev_fd, fd;
149         struct stat st;
150
151         dev_fd = open(device_path(device), O_RDONLY | O_NONBLOCK | O_CLOEXEC);
152         if (dev_fd < 0)
153                 return -EINVAL;
154
155         if (fstat(dev_fd, &st)) {
156                 close(dev_fd);
157                 return -EINVAL;
158         }
159
160         if (S_ISBLK(st.st_mode)) {
161                 if (resource_by_devno(res, sizeof(res), st.st_rdev, 0)) {
162                         close(dev_fd);
163                         return -EINVAL;
164                 }
165
166                 fd = open_resource(cd, res);
167                 close(dev_fd);
168                 if (fd < 0)
169                         return fd;
170
171                 h->flock_fd = fd;
172                 h->u.bdev.devno = st.st_rdev;
173                 h->mode = DEV_LOCK_BDEV;
174         } else if (S_ISREG(st.st_mode)) {
175                 /* workaround for nfsv4 */
176                 fd = open(device_path(device), O_RDWR | O_NONBLOCK | O_CLOEXEC);
177                 if (fd < 0)
178                         h->flock_fd = dev_fd;
179                 else {
180                         h->flock_fd = fd;
181                         close(dev_fd);
182                 }
183                 h->mode = DEV_LOCK_FILE;
184         } else {
185                 /* Wrong device type */
186                 close(dev_fd);
187                 return -EINVAL;
188         }
189
190         return 0;
191 }
192
193 static int acquire_lock_handle_by_name(struct crypt_device *cd, const char *name, struct crypt_lock_handle *h)
194 {
195         char res[PATH_MAX];
196         int fd;
197
198         h->u.name.name = strdup(name);
199         if (!h->u.name.name)
200                 return -ENOMEM;
201
202         if (resource_by_name(res, sizeof(res), name, false)) {
203                 free(h->u.name.name);
204                 return -EINVAL;
205         }
206
207         fd = open_resource(cd, res);
208         if (fd < 0) {
209                 free(h->u.name.name);
210                 return fd;
211         }
212
213         h->flock_fd = fd;
214         h->mode = DEV_LOCK_NAME;
215
216         return 0;
217 }
218
219 static void release_lock_handle(struct crypt_device *cd, struct crypt_lock_handle *h)
220 {
221         char res[PATH_MAX];
222         struct stat buf_a, buf_b;
223
224         if ((h->mode == DEV_LOCK_NAME) && /* was it name lock */
225             !flock(h->flock_fd, LOCK_EX | LOCK_NB) && /* lock to drop the file */
226             !resource_by_name(res, sizeof(res), h->u.name.name, true) && /* acquire lock resource name */
227             !fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
228             !stat(res, &buf_b) && /* does path file still exist? */
229             same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
230                 /* coverity[toctou] */
231                 if (unlink(res)) /* yes? unlink the file. lgtm[cpp/toctou-race-condition] */
232                         log_dbg(cd, "Failed to unlink resource file: %s", res);
233         }
234
235         if ((h->mode == DEV_LOCK_BDEV) && /* was it block device */
236             !flock(h->flock_fd, LOCK_EX | LOCK_NB) && /* lock to drop the file */
237             !resource_by_devno(res, sizeof(res), h->u.bdev.devno, 1) && /* acquire lock resource name */
238             !fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
239             !stat(res, &buf_b) && /* does path file still exist? */
240             same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
241                 /* coverity[toctou] */
242                 if (unlink(res)) /* yes? unlink the file. lgtm[cpp/toctou-race-condition] */
243                         log_dbg(cd, "Failed to unlink resource file: %s", res);
244         }
245
246         if (h->mode == DEV_LOCK_NAME)
247                 free(h->u.name.name);
248
249         if (close(h->flock_fd))
250                 log_dbg(cd, "Failed to close lock resource fd (%d).", h->flock_fd);
251 }
252
253 int device_locked(struct crypt_lock_handle *h)
254 {
255         return (h && (h->type == DEV_LOCK_READ || h->type == DEV_LOCK_WRITE));
256 }
257
258 int device_locked_readonly(struct crypt_lock_handle *h)
259 {
260         return (h && h->type == DEV_LOCK_READ);
261 }
262
263 static int verify_lock_handle(struct crypt_lock_handle *h)
264 {
265         char res[PATH_MAX];
266         struct stat lck_st, res_st;
267
268         /* we locked a regular file, check during device_open() instead. No reason to check now */
269         if (h->mode == DEV_LOCK_FILE)
270                 return 0;
271
272         if (h->mode == DEV_LOCK_NAME) {
273                 if (resource_by_name(res, sizeof(res), h->u.name.name, true))
274                         return -EINVAL;
275         } else if (h->mode == DEV_LOCK_BDEV) {
276                 if (resource_by_devno(res, sizeof(res), h->u.bdev.devno, true))
277                         return -EINVAL;
278         } else
279                 return -EINVAL;
280
281         if (fstat(h->flock_fd, &lck_st))
282                 return -EINVAL;
283
284         return (stat(res, &res_st) || !same_inode(lck_st, res_st)) ? -EAGAIN : 0;
285 }
286
287 static unsigned device_lock_inc(struct crypt_lock_handle *h)
288 {
289         return ++h->refcnt;
290 }
291
292 static unsigned device_lock_dec(struct crypt_lock_handle *h)
293 {
294         assert(h->refcnt);
295
296         return --h->refcnt;
297 }
298
299 static int acquire_and_verify(struct crypt_device *cd, struct device *device, const char *resource, int flock_op, struct crypt_lock_handle **lock)
300 {
301         int r;
302         struct crypt_lock_handle *h;
303
304         if (device && resource)
305                 return -EINVAL;
306
307         if (!(h = malloc(sizeof(*h))))
308                 return -ENOMEM;
309
310         do {
311                 r = device ? acquire_lock_handle(cd, device, h) : acquire_lock_handle_by_name(cd, resource, h);
312                 if (r < 0)
313                         break;
314
315                 if (flock(h->flock_fd, flock_op)) {
316                         log_dbg(cd, "Flock on fd %d failed with errno %d.", h->flock_fd, errno);
317                         r = (errno == EWOULDBLOCK) ? -EBUSY : -EINVAL;
318                         release_lock_handle(cd, h);
319                         break;
320                 }
321
322                 log_dbg(cd, "Verifying lock handle for %s.", device ? device_path(device) : resource);
323
324                 /*
325                  * check whether another libcryptsetup process removed resource file before this
326                  * one managed to flock() it. See release_lock_handle() for details
327                  */
328                 r = verify_lock_handle(h);
329                 if (r < 0) {
330                         if (flock(h->flock_fd, LOCK_UN))
331                                 log_dbg(cd, "flock on fd %d failed.", h->flock_fd);
332                         release_lock_handle(cd, h);
333                         log_dbg(cd, "Lock handle verification failed.");
334                 }
335         } while (r == -EAGAIN);
336
337         if (r < 0) {
338                 free(h);
339                 return r;
340         }
341
342         *lock = h;
343
344         return 0;
345 }
346
347 int device_read_lock_internal(struct crypt_device *cd, struct device *device)
348 {
349         int r;
350         struct crypt_lock_handle *h;
351
352         if (!device)
353                 return -EINVAL;
354
355         h = device_get_lock_handle(device);
356
357         if (device_locked(h)) {
358                 device_lock_inc(h);
359                 log_dbg(cd, "Device %s READ lock (or higher) already held.", device_path(device));
360                 return 0;
361         }
362
363         log_dbg(cd, "Acquiring read lock for device %s.", device_path(device));
364
365         r = acquire_and_verify(cd, device, NULL, LOCK_SH, &h);
366         if (r < 0)
367                 return r;
368
369         h->type = DEV_LOCK_READ;
370         h->refcnt = 1;
371         device_set_lock_handle(device, h);
372
373         log_dbg(cd, "Device %s READ lock taken.", device_path(device));
374
375         return 0;
376 }
377
378 int device_write_lock_internal(struct crypt_device *cd, struct device *device)
379 {
380         int r;
381         struct crypt_lock_handle *h;
382
383         if (!device)
384                 return -EINVAL;
385
386         h = device_get_lock_handle(device);
387
388         if (device_locked(h)) {
389                 log_dbg(cd, "Device %s WRITE lock already held.", device_path(device));
390                 return device_lock_inc(h);
391         }
392
393         log_dbg(cd, "Acquiring write lock for device %s.", device_path(device));
394
395         r = acquire_and_verify(cd, device, NULL, LOCK_EX, &h);
396         if (r < 0)
397                 return r;
398
399         h->type = DEV_LOCK_WRITE;
400         h->refcnt = 1;
401         device_set_lock_handle(device, h);
402
403         log_dbg(cd, "Device %s WRITE lock taken.", device_path(device));
404
405         return 1;
406 }
407
408 int crypt_read_lock(struct crypt_device *cd, const char *resource, bool blocking, struct crypt_lock_handle **lock)
409 {
410         int r;
411         struct crypt_lock_handle *h;
412
413         if (!resource)
414                 return -EINVAL;
415
416         log_dbg(cd, "Acquiring %sblocking read lock for resource %s.", blocking ? "" : "non", resource);
417
418         r = acquire_and_verify(cd, NULL, resource, LOCK_SH | (blocking ? 0 : LOCK_NB), &h);
419         if (r < 0)
420                 return r;
421
422         h->type = DEV_LOCK_READ;
423         h->refcnt = 1;
424
425         log_dbg(cd, "READ lock for resource %s taken.", resource);
426
427         *lock = h;
428
429         return 0;
430 }
431
432 int crypt_write_lock(struct crypt_device *cd, const char *resource, bool blocking, struct crypt_lock_handle **lock)
433 {
434         int r;
435         struct crypt_lock_handle *h;
436
437         if (!resource)
438                 return -EINVAL;
439
440         log_dbg(cd, "Acquiring %sblocking write lock for resource %s.", blocking ? "" : "non", resource);
441
442         r = acquire_and_verify(cd, NULL, resource, LOCK_EX | (blocking ? 0 : LOCK_NB), &h);
443         if (r < 0)
444                 return r;
445
446         h->type = DEV_LOCK_WRITE;
447         h->refcnt = 1;
448
449         log_dbg(cd, "WRITE lock for resource %s taken.", resource);
450
451         *lock = h;
452
453         return 0;
454 }
455
456 static void unlock_internal(struct crypt_device *cd, struct crypt_lock_handle *h)
457 {
458         if (flock(h->flock_fd, LOCK_UN))
459                 log_dbg(cd, "flock on fd %d failed.", h->flock_fd);
460         release_lock_handle(cd, h);
461         free(h);
462 }
463
464 void crypt_unlock_internal(struct crypt_device *cd, struct crypt_lock_handle *h)
465 {
466         if (!h)
467                 return;
468
469         /* nested locks are illegal */
470         assert(!device_lock_dec(h));
471
472         log_dbg(cd, "Unlocking %s lock for resource %s.",
473                 device_locked_readonly(h) ? "READ" : "WRITE", h->u.name.name);
474
475         unlock_internal(cd, h);
476 }
477
478 void device_unlock_internal(struct crypt_device *cd, struct device *device)
479 {
480         bool readonly;
481         struct crypt_lock_handle *h = device_get_lock_handle(device);
482         unsigned u = device_lock_dec(h);
483
484         if (u)
485                 return;
486
487         readonly = device_locked_readonly(h);
488
489         unlock_internal(cd, h);
490
491         log_dbg(cd, "Device %s %s lock released.", device_path(device),
492                 readonly ? "READ" : "WRITE");
493
494         device_set_lock_handle(device, NULL);
495 }
496
497 int device_locked_verify(struct crypt_device *cd, int dev_fd, struct crypt_lock_handle *h)
498 {
499         char res[PATH_MAX];
500         struct stat dev_st, lck_st, st;
501
502         if (fstat(dev_fd, &dev_st) || fstat(h->flock_fd, &lck_st))
503                 return 1;
504
505         /* if device handle is regular file the handle must match the lock handle */
506         if (S_ISREG(dev_st.st_mode)) {
507                 log_dbg(cd, "Verifying locked device handle (regular file)");
508                 if (!same_inode(dev_st, lck_st))
509                         return 1;
510         } else if (S_ISBLK(dev_st.st_mode)) {
511                 log_dbg(cd, "Verifying locked device handle (bdev)");
512                 if (resource_by_devno(res, sizeof(res), dev_st.st_rdev, 1) ||
513                     stat(res, &st) ||
514                     !same_inode(lck_st, st))
515                         return 1;
516         } else
517                 return 1;
518
519         return 0;
520 }