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