]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/src/context_loopdev.c
mount: Fix race in loop device reuse code
[thirdparty/util-linux.git] / libmount / src / context_loopdev.c
CommitLineData
2c37ca7c 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
7f8b2bf3 2/*
2c37ca7c 3 * This file is part of libmount from util-linux project.
7f8b2bf3 4 *
2c37ca7c
KZ
5 * Copyright (C) 2011-2018 Karel Zak <kzak@redhat.com>
6 *
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
7f8b2bf3
KZ
11 */
12
13/*
14 * DOCS: - "lo@" prefix for fstype is unsupported
7f8b2bf3
KZ
15 */
16
17#include <blkid.h>
7b46647d 18#include <stdbool.h>
7f8b2bf3
KZ
19
20#include "mountP.h"
21#include "loopdev.h"
22#include "linux_version.h"
23
24
25int mnt_context_is_loopdev(struct libmnt_context *cxt)
26{
27 const char *type, *src;
7f8b2bf3
KZ
28
29 assert(cxt);
c8512236 30
7f8b2bf3
KZ
31 /* The mount flags have to be merged, otherwise we have to use
32 * expensive mnt_context_get_user_mflags() instead of cxt->user_mountflags. */
33 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
34
35 if (!cxt->fs)
36 return 0;
37 src = mnt_fs_get_srcpath(cxt->fs);
38 if (!src)
39 return 0; /* backing file not set */
40
41 if (cxt->user_mountflags & (MNT_MS_LOOP |
42 MNT_MS_OFFSET |
5cf05c71 43 MNT_MS_SIZELIMIT)) {
c8512236 44
7bbde59c 45 DBG(LOOP, ul_debugobj(cxt, "loopdev specific options detected"));
7f8b2bf3 46 return 1;
c8512236 47 }
7f8b2bf3 48
6498ece0
KZ
49 if ((cxt->mountflags & (MS_BIND | MS_MOVE))
50 || mnt_context_propagation_only(cxt))
7f8b2bf3
KZ
51 return 0;
52
c8512236
KZ
53 /* Automatically create a loop device from a regular file if a
54 * filesystem is not specified or the filesystem is known for libblkid
55 * (these filesystems work with block devices only). The file size
d58b3157
OO
56 * should be at least 1KiB, otherwise we will create an empty loopdev with
57 * no mountable filesystem...
7f8b2bf3 58 *
d58b3157 59 * Note that there is no restriction (on kernel side) that would prevent a regular
7f8b2bf3
KZ
60 * file as a mount(2) source argument. A filesystem that is able to mount
61 * regular files could be implemented.
62 */
63 type = mnt_fs_get_fstype(cxt->fs);
7f8b2bf3 64
ac8697d6 65 if (mnt_fs_is_regularfs(cxt->fs) &&
7f8b2bf3
KZ
66 (!type || strcmp(type, "auto") == 0 || blkid_known_fstype(type))) {
67 struct stat st;
68
c8512236 69 if (stat(src, &st) == 0 && S_ISREG(st.st_mode) &&
e8cd1819 70 st.st_size > 1024) {
7bbde59c 71 DBG(LOOP, ul_debugobj(cxt, "automatically enabling loop= option"));
e8cd1819
KZ
72 cxt->user_mountflags |= MNT_MS_LOOP;
73 mnt_optstr_append_option(&cxt->fs->user_optstr, "loop", NULL);
c8512236 74 return 1;
e8cd1819 75 }
7f8b2bf3
KZ
76 }
77
c8512236 78 return 0;
7f8b2bf3
KZ
79}
80
8b470b20 81
d58b3157 82/* Check if there already exists a mounted loop device on the mountpoint node
8b470b20
KZ
83 * with the same parameters.
84 */
ba2bdf41
KZ
85static int __attribute__((nonnull))
86is_mounted_same_loopfile(struct libmnt_context *cxt,
8b470b20
KZ
87 const char *target,
88 const char *backing_file,
89 uint64_t offset)
90{
91 struct libmnt_table *tb;
92 struct libmnt_iter itr;
93 struct libmnt_fs *fs;
94 struct libmnt_cache *cache;
68c41a5f
KZ
95 const char *bf;
96 int rc = 0;
cddd2eaa 97 struct libmnt_ns *ns_old;
8b470b20
KZ
98
99 assert(cxt);
100 assert(cxt->fs);
101 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
102
372d410d 103 if (mnt_context_get_mtab(cxt, &tb))
8b470b20
KZ
104 return 0;
105
cddd2eaa
VD
106 ns_old = mnt_context_switch_target_ns(cxt);
107 if (!ns_old)
108 return -MNT_ERR_NAMESPACE;
109
7bbde59c 110 DBG(LOOP, ul_debugobj(cxt, "checking if %s mounted on %s",
8b470b20
KZ
111 backing_file, target));
112
113 cache = mnt_context_get_cache(cxt);
114 mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
115
68c41a5f
KZ
116 bf = cache ? mnt_resolve_path(backing_file, cache) : backing_file;
117
d58b3157 118 /* Search for a mountpoint node in mtab, proceed if any of these have the
8b470b20
KZ
119 * loop option set or the device is a loop device
120 */
68c41a5f 121 while (rc == 0 && mnt_table_next_fs(tb, &itr, &fs) == 0) {
8b470b20
KZ
122 const char *src = mnt_fs_get_source(fs);
123 const char *opts = mnt_fs_get_user_options(fs);
124 char *val;
125 size_t len;
8b470b20
KZ
126
127 if (!src || !mnt_fs_match_target(fs, target, cache))
128 continue;
129
68c41a5f
KZ
130 rc = 0;
131
8b470b20 132 if (strncmp(src, "/dev/loop", 9) == 0) {
74a4705a 133 rc = loopdev_is_used((char *) src, bf, offset, 0, LOOPDEV_FL_OFFSET);
8b470b20
KZ
134
135 } else if (opts && (cxt->user_mountflags & MNT_MS_LOOP) &&
136 mnt_optstr_get_option(opts, "loop", &val, &len) == 0 && val) {
137
138 val = strndup(val, len);
74a4705a 139 rc = loopdev_is_used((char *) val, bf, offset, 0, LOOPDEV_FL_OFFSET);
8b470b20
KZ
140 free(val);
141 }
8b470b20 142 }
68c41a5f 143 if (rc)
7bbde59c 144 DBG(LOOP, ul_debugobj(cxt, "%s already mounted", backing_file));
cddd2eaa
VD
145
146 if (!mnt_context_switch_ns(cxt, ns_old))
147 return -MNT_ERR_NAMESPACE;
68c41a5f 148 return rc;
8b470b20
KZ
149}
150
7f8b2bf3
KZ
151int mnt_context_setup_loopdev(struct libmnt_context *cxt)
152{
f0d3ff0a 153 const char *backing_file, *optstr, *loopdev = NULL;
6e258026 154 char *val = NULL, *loopval = NULL;
7f8b2bf3
KZ
155 size_t len;
156 struct loopdev_cxt lc;
b9fd3340
KZ
157 int rc = 0, lo_flags = 0;
158 uint64_t offset = 0, sizelimit = 0;
7b46647d 159 bool reuse = FALSE;
7f8b2bf3 160
98d391c0 161 assert(cxt);
7f8b2bf3
KZ
162 assert(cxt->fs);
163 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
164
165 backing_file = mnt_fs_get_srcpath(cxt->fs);
166 if (!backing_file)
167 return -EINVAL;
168
7bbde59c 169 DBG(LOOP, ul_debugobj(cxt, "trying to setup device for %s", backing_file));
7f8b2bf3
KZ
170
171 if (cxt->mountflags & MS_RDONLY) {
7bbde59c 172 DBG(LOOP, ul_debugobj(cxt, "enabling READ-ONLY flag"));
7f8b2bf3
KZ
173 lo_flags |= LO_FLAGS_READ_ONLY;
174 }
365e5a7c 175
b9fd3340 176 optstr = mnt_fs_get_user_options(cxt->fs);
7f8b2bf3 177
b9fd3340
KZ
178 /*
179 * loop=
180 */
181 if (rc == 0 && (cxt->user_mountflags & MNT_MS_LOOP) &&
182 mnt_optstr_get_option(optstr, "loop", &val, &len) == 0 && val) {
6e258026
SB
183 loopval = strndup(val, len);
184 rc = loopval ? 0 : -ENOMEM;
b9fd3340
KZ
185 }
186
187 /*
188 * offset=
189 */
190 if (rc == 0 && (cxt->user_mountflags & MNT_MS_OFFSET) &&
191 mnt_optstr_get_option(optstr, "offset", &val, &len) == 0) {
192 rc = mnt_parse_offset(val, len, &offset);
61f5ff6c 193 if (rc) {
7bbde59c 194 DBG(LOOP, ul_debugobj(cxt, "failed to parse offset="));
61f5ff6c
KZ
195 rc = -MNT_ERR_MOUNTOPT;
196 }
7f8b2bf3
KZ
197 }
198
b9fd3340
KZ
199 /*
200 * sizelimit=
201 */
202 if (rc == 0 && (cxt->user_mountflags & MNT_MS_SIZELIMIT) &&
203 mnt_optstr_get_option(optstr, "sizelimit", &val, &len) == 0) {
204 rc = mnt_parse_offset(val, len, &sizelimit);
61f5ff6c 205 if (rc) {
7bbde59c 206 DBG(LOOP, ul_debugobj(cxt, "failed to parse sizelimit="));
61f5ff6c
KZ
207 rc = -MNT_ERR_MOUNTOPT;
208 }
b9fd3340
KZ
209 }
210
1a7a421e
KZ
211 /*
212 * encryption=
213 */
214 if (rc == 0 && (cxt->user_mountflags & MNT_MS_ENCRYPTION) &&
215 mnt_optstr_get_option(optstr, "encryption", &val, &len) == 0) {
7bbde59c 216 DBG(LOOP, ul_debugobj(cxt, "encryption no longer supported"));
5cf05c71 217 rc = -MNT_ERR_MOUNTOPT;
1a7a421e
KZ
218 }
219
8b470b20
KZ
220 if (rc == 0 && is_mounted_same_loopfile(cxt,
221 mnt_context_get_target(cxt),
222 backing_file, offset))
223 rc = -EBUSY;
224
6e258026
SB
225 if (rc)
226 goto done_no_deinit;
227
bdf46c4d
SB
228 /* It is possible to mount the same file more times. If we set more
229 * than one loop device referring to the same file, kernel has no
230 * mechanism to detect it. To prevent data corruption, the same loop
231 * device has to be recycled.
232 */
8efad715
SB
233 if (backing_file) {
234 rc = loopcxt_init(&lc, 0);
235 if (rc)
236 goto done_no_deinit;
237
dff7e160
KZ
238 rc = loopcxt_find_overlap(&lc, backing_file, offset, sizelimit);
239 switch (rc) {
240 case 0: /* not found */
73afd3f8 241 DBG(LOOP, ul_debugobj(cxt, "not found overlapping loopdev"));
dff7e160
KZ
242 loopcxt_deinit(&lc);
243 break;
244
245 case 1: /* overlap */
73afd3f8 246 DBG(LOOP, ul_debugobj(cxt, "overlapping %s detected",
dff7e160
KZ
247 loopcxt_get_device(&lc)));
248 rc = -MNT_ERR_LOOPOVERLAP;
8efad715 249 goto done;
dff7e160
KZ
250
251 case 2: /* overlap -- full size and offset match (reuse) */
252 {
22a64b02 253 uint32_t lc_encrypt_type = 0;
8efad715 254
dff7e160 255 DBG(LOOP, ul_debugobj(cxt, "re-using existing loop device %s",
8efad715
SB
256 loopcxt_get_device(&lc)));
257
3e1fc3bb
JK
258 /* Open loop device to block device autoclear... */
259 if (loopcxt_get_fd(&lc) < 0) {
260 DBG(LOOP, ul_debugobj(cxt, "failed to get loopdev FD"));
261 rc = -errno;
262 goto done;
263 }
264
265 /*
266 * Now that we certainly have the loop device open,
267 * verify the loop device was not autocleared in the
268 * mean time.
269 */
270 if (!loopcxt_get_info(&lc)) {
271 DBG(LOOP, ul_debugobj(cxt, "lost race with %s teardown",
272 loopcxt_get_device(&lc)));
273 loopcxt_deinit(&lc);
274 break;
275 }
276
8efad715 277 /* Once a loop is initialized RO, there is no
dff7e160
KZ
278 * way to change its parameters. */
279 if (loopcxt_is_readonly(&lc)
280 && !(lo_flags & LO_FLAGS_READ_ONLY)) {
281 DBG(LOOP, ul_debugobj(cxt, "%s is read-only",
282 loopcxt_get_device(&lc)));
8efad715
SB
283 rc = -EROFS;
284 goto done;
285 }
286
dff7e160
KZ
287 /* This is no more supported, but check to be safe. */
288 if (loopcxt_get_encrypt_type(&lc, &lc_encrypt_type) == 0
289 && lc_encrypt_type != LO_CRYPT_NONE) {
8efad715
SB
290 DBG(LOOP, ul_debugobj(cxt, "encryption no longer supported for device %s",
291 loopcxt_get_device(&lc)));
292 rc = -MNT_ERR_LOOPOVERLAP;
293 goto done;
294 }
dff7e160 295 rc = 0;
3789806d
SB
296 /* loop= used with argument. Conflict will occur. */
297 if (loopval) {
298 rc = -MNT_ERR_LOOPOVERLAP;
299 goto done;
7b46647d
SB
300 } else {
301 reuse = TRUE;
3789806d 302 goto success;
7b46647d 303 }
8efad715 304 }
dff7e160 305 default: /* error */
bdf46c4d
SB
306 goto done;
307 }
bdf46c4d 308 }
bdf46c4d 309
dff7e160 310 DBG(LOOP, ul_debugobj(cxt, "not found; create a new loop device"));
6e258026 311 rc = loopcxt_init(&lc, 0);
441cdba9
SB
312 if (rc)
313 goto done_no_deinit;
314 if (loopval) {
6e258026
SB
315 rc = loopcxt_set_device(&lc, loopval);
316 if (rc == 0)
317 loopdev = loopcxt_get_device(&lc);
318 }
b9fd3340
KZ
319 if (rc)
320 goto done;
321
7f8b2bf3
KZ
322 /* since 2.6.37 we don't have to store backing filename to mtab
323 * because kernel provides the name in /sys.
324 */
325 if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
150e696d 326 !mnt_context_mtab_writable(cxt)) {
7bbde59c 327 DBG(LOOP, ul_debugobj(cxt, "enabling AUTOCLEAR flag"));
7f8b2bf3
KZ
328 lo_flags |= LO_FLAGS_AUTOCLEAR;
329 }
330
331 do {
332 /* found free device */
333 if (!loopdev) {
334 rc = loopcxt_find_unused(&lc);
335 if (rc)
336 goto done;
7bbde59c 337 DBG(LOOP, ul_debugobj(cxt, "trying to use %s",
7f8b2bf3
KZ
338 loopcxt_get_device(&lc)));
339 }
340
b9fd3340
KZ
341 /* set device attributes
342 * -- note that loopcxt_find_unused() resets "lc"
343 */
7f8b2bf3 344 rc = loopcxt_set_backing_file(&lc, backing_file);
7f8b2bf3 345
b9fd3340
KZ
346 if (!rc && offset)
347 rc = loopcxt_set_offset(&lc, offset);
348 if (!rc && sizelimit)
349 rc = loopcxt_set_sizelimit(&lc, sizelimit);
350 if (!rc)
351 loopcxt_set_flags(&lc, lo_flags);
352 if (rc) {
7bbde59c 353 DBG(LOOP, ul_debugobj(cxt, "failed to set loop attributes"));
b9fd3340
KZ
354 goto done;
355 }
7f8b2bf3
KZ
356
357 /* setup the device */
358 rc = loopcxt_setup_device(&lc);
359 if (!rc)
360 break; /* success */
361
362 if (loopdev || rc != -EBUSY) {
7bbde59c 363 DBG(LOOP, ul_debugobj(cxt, "failed to setup device"));
82756a74 364 rc = -MNT_ERR_LOOPDEV;
b9fd3340 365 goto done;
7f8b2bf3 366 }
7bbde59c 367 DBG(LOOP, ul_debugobj(cxt, "device stolen...trying again"));
7f8b2bf3
KZ
368 } while (1);
369
bdf46c4d 370success:
7f8b2bf3
KZ
371 if (!rc)
372 rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc));
373
374 if (!rc) {
375 /* success */
376 cxt->flags |= MNT_FL_LOOPDEV_READY;
377
7b46647d
SB
378 if (reuse || ( (cxt->user_mountflags & MNT_MS_LOOP) &&
379 loopcxt_is_autoclear(&lc))) {
7f8b2bf3 380 /*
d58b3157 381 * autoclear flag accepted by the kernel, don't store
7f8b2bf3
KZ
382 * the "loop=" option to mtab.
383 */
7bbde59c 384 DBG(LOOP, ul_debugobj(cxt, "removing unnecessary loop= from mtab"));
7f8b2bf3 385 cxt->user_mountflags &= ~MNT_MS_LOOP;
f0d3ff0a
KZ
386 mnt_optstr_remove_option(&cxt->fs->user_optstr, "loop");
387 }
7f8b2bf3
KZ
388
389 if (!(cxt->mountflags & MS_RDONLY) &&
390 loopcxt_is_readonly(&lc))
391 /*
392 * mount planned read-write, but loopdev is read-only,
393 * let's fix mount options...
394 */
f9906424 395 mnt_context_set_mflags(cxt, cxt->mountflags | MS_RDONLY);
7f8b2bf3
KZ
396
397 /* we have to keep the device open until mount(1),
d58b3157 398 * otherwise it will be auto-cleared by kernel
7f8b2bf3
KZ
399 */
400 cxt->loopdev_fd = loopcxt_get_fd(&lc);
dff7e160
KZ
401 if (cxt->loopdev_fd < 0) {
402 DBG(LOOP, ul_debugobj(cxt, "failed to get loopdev FD"));
403 rc = -errno;
404 } else
405 loopcxt_set_fd(&lc, -1, 0);
7f8b2bf3
KZ
406 }
407done:
408 loopcxt_deinit(&lc);
6e258026
SB
409done_no_deinit:
410 free(loopval);
7f8b2bf3
KZ
411 return rc;
412}
413
414/*
415 * Deletes loop device
416 */
417int mnt_context_delete_loopdev(struct libmnt_context *cxt)
418{
419 const char *src;
420 int rc;
421
422 assert(cxt);
423 assert(cxt->fs);
424
425 src = mnt_fs_get_srcpath(cxt->fs);
426 if (!src)
427 return -EINVAL;
428
429 if (cxt->loopdev_fd > -1)
430 close(cxt->loopdev_fd);
431
432 rc = loopdev_delete(src);
433 cxt->flags &= ~MNT_FL_LOOPDEV_READY;
434 cxt->loopdev_fd = -1;
435
7bbde59c 436 DBG(LOOP, ul_debugobj(cxt, "deleted [rc=%d]", rc));
7f8b2bf3
KZ
437 return rc;
438}
439
440/*
441 * Clears loopdev stuff in context, should be called after
442 * failed or successful mount(2).
443 */
444int mnt_context_clear_loopdev(struct libmnt_context *cxt)
445{
446 assert(cxt);
447
448 if (mnt_context_get_status(cxt) == 0 &&
449 (cxt->flags & MNT_FL_LOOPDEV_READY)) {
450 /*
451 * mount(2) failed, delete loopdev
452 */
453 mnt_context_delete_loopdev(cxt);
454
455 } else if (cxt->loopdev_fd > -1) {
456 /*
457 * mount(2) success, close the device
458 */
7bbde59c 459 DBG(LOOP, ul_debugobj(cxt, "closing FD"));
7f8b2bf3
KZ
460 close(cxt->loopdev_fd);
461 }
462 cxt->loopdev_fd = -1;
463 return 0;
464}
465