1  /* SPDX-License-Identifier: LGPL-2.1-or-later */
       2  /*
       3   * This file is part of libmount from util-linux project.
       4   *
       5   * Copyright (C) 2011-2022 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.
      11   *
      12   * Please, see the comment in libmount/src/hooks.c to understand how hooks work.
      13   */
      14  #include <blkid.h>
      15  #include <stdbool.h>
      16  
      17  #include "mountP.h"
      18  #include "loopdev.h"
      19  #include "strutils.h"
      20  #include "linux_version.h"
      21  
      22  struct hook_data {
      23  	int loopdev_fd;
      24  };
      25  
      26  /* de-initiallize this module */
      27  static int hookset_deinit(struct libmnt_context *cxt, const struct libmnt_hookset *hs)
      28  {
      29  	void *data;
      30  
      31  	DBG(HOOK, ul_debugobj(hs, "deinit '%s'", hs->name));
      32  
      33  	/* remove all our hooks */
      34  	while (mnt_context_remove_hook(cxt, hs, 0, &data) == 0) {
      35  		free(data);
      36  		data = NULL;
      37  	}
      38  
      39  	return 0;
      40  }
      41  
      42  static inline struct hook_data *new_hook_data(void)
      43  {
      44  	struct hook_data *hd = calloc(1, sizeof(*hd));
      45  
      46  	if (!hd)
      47  		return NULL;
      48  
      49  	hd->loopdev_fd =  -1;
      50  	return hd;
      51  }
      52  
      53  /* Check if there already exists a mounted loop device on the mountpoint node
      54   * with the same parameters.
      55   */
      56  static int __attribute__((nonnull))
      57  is_mounted_same_loopfile(struct libmnt_context *cxt,
      58  				    const char *target,
      59  				    const char *backing_file,
      60  				    uint64_t offset)
      61  {
      62  	struct libmnt_table *tb = NULL;
      63  	struct libmnt_iter itr;
      64  	struct libmnt_fs *fs;
      65  	struct libmnt_cache *cache;
      66  	const char *bf;
      67  	int rc = 0;
      68  	struct libmnt_ns *ns_old;
      69  	unsigned long flags = 0;
      70  
      71  	assert(cxt);
      72  	assert(cxt->fs);
      73  	assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
      74  
      75  	if (mnt_context_get_mountinfo(cxt, &tb))
      76  		return 0;
      77  
      78  	ns_old = mnt_context_switch_target_ns(cxt);
      79  	if (!ns_old)
      80  		return -MNT_ERR_NAMESPACE;
      81  
      82  	DBG(LOOP, ul_debugobj(cxt, "checking if %s mounted on %s",
      83  				backing_file, target));
      84  
      85  	rc = mnt_context_get_user_mflags(cxt, &flags);
      86  	if (rc)
      87  		return 0;
      88  
      89  	cache = mnt_context_get_cache(cxt);
      90  	mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
      91  
      92  	bf = cache ? mnt_resolve_path(backing_file, cache) : backing_file;
      93  
      94  	/* Search for a mountpoint node in mountinfo, proceed if any of these have the
      95  	 * loop option set or the device is a loop device
      96  	 */
      97  	while (rc == 0 && mnt_table_next_fs(tb, &itr, &fs) == 0) {
      98  		const char *src = mnt_fs_get_source(fs);
      99  		const char *opts = mnt_fs_get_user_options(fs);
     100  		char *val;
     101  		size_t len;
     102  
     103  		if (!src || !mnt_fs_match_target(fs, target, cache))
     104  			continue;
     105  
     106  		rc = 0;
     107  
     108  		if (strncmp(src, "/dev/loop", 9) == 0) {
     109  			rc = loopdev_is_used((char *) src, bf, offset, 0, LOOPDEV_FL_OFFSET);
     110  
     111  		} else if (opts && (flags & MNT_MS_LOOP) &&
     112  		    mnt_optstr_get_option(opts, "loop", &val, &len) == 0 && val) {
     113  
     114  			val = strndup(val, len);
     115  			rc = loopdev_is_used((char *) val, bf, offset, 0, LOOPDEV_FL_OFFSET);
     116  			free(val);
     117  		}
     118  	}
     119  	if (rc)
     120  		DBG(LOOP, ul_debugobj(cxt, "%s already mounted", backing_file));
     121  
     122  	if (!mnt_context_switch_ns(cxt, ns_old))
     123  		return -MNT_ERR_NAMESPACE;
     124  	return rc;
     125  }
     126  
     127  static int setup_loopdev(struct libmnt_context *cxt,
     128  			 struct libmnt_optlist *ol, struct hook_data *hd)
     129  {
     130  	const char *backing_file, *loopdev = NULL;
     131  	struct loopdev_cxt lc;
     132  	int rc = 0, lo_flags = 0;
     133  	uint64_t offset = 0, sizelimit = 0;
     134  	bool reuse = FALSE;
     135  	struct libmnt_opt *opt, *loopopt = NULL;
     136  
     137  	backing_file = mnt_fs_get_srcpath(cxt->fs);
     138  	if (!backing_file)
     139  		return -EINVAL;
     140  
     141  	DBG(LOOP, ul_debugobj(cxt, "trying to setup device for %s", backing_file));
     142  
     143  	ol = mnt_context_get_optlist(cxt);
     144  	if (!ol)
     145  		return -ENOMEM;
     146  
     147  	if (mnt_optlist_is_rdonly(ol)) {
     148  		DBG(LOOP, ul_debugobj(cxt, "enabling READ-ONLY flag"));
     149  		lo_flags |= LO_FLAGS_READ_ONLY;
     150  	}
     151  
     152  	/*
     153  	 * loop=
     154  	 */
     155  	if (!rc)
     156  		loopopt = mnt_optlist_get_opt(ol, MNT_MS_LOOP, cxt->map_userspace);
     157  
     158  	/*
     159  	 * offset=
     160  	 */
     161  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_OFFSET, cxt->map_userspace))
     162  	    && mnt_opt_has_value(opt)) {
     163  		if (strtosize(mnt_opt_get_value(opt), &offset)) {
     164  			DBG(LOOP, ul_debugobj(cxt, "failed to parse offset="));
     165  			rc = -MNT_ERR_MOUNTOPT;
     166  		}
     167  	}
     168  
     169  	/*
     170  	 * sizelimit=
     171  	 */
     172  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_SIZELIMIT, cxt->map_userspace))
     173  	    && mnt_opt_has_value(opt)) {
     174  		if (strtosize(mnt_opt_get_value(opt), &sizelimit)) {
     175  			DBG(LOOP, ul_debugobj(cxt, "failed to parse sizelimit="));
     176  			rc = -MNT_ERR_MOUNTOPT;
     177  		}
     178  	}
     179  
     180  	/*
     181  	 * encryption=
     182  	 */
     183  	if (!rc && mnt_optlist_get_opt(ol, MNT_MS_ENCRYPTION, cxt->map_userspace)) {
     184  		DBG(LOOP, ul_debugobj(cxt, "encryption no longer supported"));
     185  		rc = -MNT_ERR_MOUNTOPT;
     186  	}
     187  
     188  	if (!rc && is_mounted_same_loopfile(cxt,
     189  				mnt_context_get_target(cxt),
     190  				backing_file, offset))
     191  		rc = -EBUSY;
     192  
     193  	if (rc)
     194  		goto done_no_deinit;
     195  
     196  	/* It is possible to mount the same file more times. If we set more
     197  	 * than one loop device referring to the same file, kernel has no
     198  	 * mechanism to detect it. To prevent data corruption, the same loop
     199  	 * device has to be recycled.
     200  	*/
     201  	if (backing_file) {
     202  		rc = loopcxt_init(&lc, 0);
     203  		if (rc)
     204  			goto done_no_deinit;
     205  
     206  		rc = loopcxt_find_overlap(&lc, backing_file, offset, sizelimit);
     207  		switch (rc) {
     208  		case 0: /* not found */
     209  			DBG(LOOP, ul_debugobj(cxt, "not found overlapping loopdev"));
     210  			loopcxt_deinit(&lc);
     211  			break;
     212  
     213  		case 1:	/* overlap */
     214  			DBG(LOOP, ul_debugobj(cxt, "overlapping %s detected",
     215  						loopcxt_get_device(&lc)));
     216  			rc = -MNT_ERR_LOOPOVERLAP;
     217  			goto done;
     218  
     219  		case 2: /* overlap -- full size and offset match (reuse) */
     220  		{
     221  			uint32_t lc_encrypt_type = 0;
     222  
     223  			DBG(LOOP, ul_debugobj(cxt, "re-using existing loop device %s",
     224  				loopcxt_get_device(&lc)));
     225  
     226  			/* Open loop device to block device autoclear... */
     227  			if (loopcxt_get_fd(&lc) < 0) {
     228  				DBG(LOOP, ul_debugobj(cxt, "failed to get loopdev FD"));
     229  				rc = -errno;
     230  				goto done;
     231  			}
     232  
     233  			/*
     234  			 * Now that we certainly have the loop device open,
     235  			 * verify the loop device was not autocleared in the
     236  			 * mean time.
     237  			 */
     238  			if (!loopcxt_get_info(&lc)) {
     239  				DBG(LOOP, ul_debugobj(cxt, "lost race with %s teardown",
     240  						loopcxt_get_device(&lc)));
     241  				loopcxt_deinit(&lc);
     242  				break;
     243  			}
     244  
     245  			/* Once a loop is initialized RO, there is no
     246  			 * way to change its parameters. */
     247  			if (loopcxt_is_readonly(&lc)
     248  			    && !(lo_flags & LO_FLAGS_READ_ONLY)) {
     249  				DBG(LOOP, ul_debugobj(cxt, "%s is read-only",
     250  						loopcxt_get_device(&lc)));
     251  				rc = -EROFS;
     252  				goto done;
     253  			}
     254  
     255  			/* This is no more supported, but check to be safe. */
     256  			if (loopcxt_get_encrypt_type(&lc, &lc_encrypt_type) == 0
     257  			    && lc_encrypt_type != LO_CRYPT_NONE) {
     258  				DBG(LOOP, ul_debugobj(cxt, "encryption no longer supported for device %s",
     259  					loopcxt_get_device(&lc)));
     260  				rc = -MNT_ERR_LOOPOVERLAP;
     261  				goto done;
     262  			}
     263  			rc = 0;
     264  			/* loop= used with argument. Conflict will occur. */
     265  			if (mnt_opt_has_value(loopopt)) {
     266  				rc = -MNT_ERR_LOOPOVERLAP;
     267  				goto done;
     268  			} else {
     269  				reuse = TRUE;
     270  				goto success;
     271  			}
     272  		}
     273  		default: /* error */
     274  			goto done;
     275  		}
     276  	}
     277  
     278  	DBG(LOOP, ul_debugobj(cxt, "not found; create a new loop device"));
     279  	rc = loopcxt_init(&lc, 0);
     280  	if (rc)
     281  		goto done_no_deinit;
     282  	if (mnt_opt_has_value(loopopt)) {
     283  		rc = loopcxt_set_device(&lc, mnt_opt_get_value(loopopt));
     284  		if (rc == 0)
     285  			loopdev = loopcxt_get_device(&lc);
     286  	}
     287  	if (rc)
     288  		goto done;
     289  
     290  	/* since 2.6.37 we don't have to store backing filename to mountinfo
     291  	 * because kernel provides the name in /sys.
     292  	 */
     293  	if (get_linux_version() >= KERNEL_VERSION(2, 6, 37)) {
     294  		DBG(LOOP, ul_debugobj(cxt, "enabling AUTOCLEAR flag"));
     295  		lo_flags |= LO_FLAGS_AUTOCLEAR;
     296  	}
     297  
     298  	do {
     299  		/* found free device */
     300  		if (!loopdev) {
     301  			rc = loopcxt_find_unused(&lc);
     302  			if (rc)
     303  				goto done;
     304  			DBG(LOOP, ul_debugobj(cxt, "trying to use %s",
     305  						loopcxt_get_device(&lc)));
     306  		}
     307  
     308  		/* set device attributes
     309  		 * -- note that loopcxt_find_unused() resets "lc"
     310  		 */
     311  		rc = loopcxt_set_backing_file(&lc, backing_file);
     312  
     313  		if (!rc && offset)
     314  			rc = loopcxt_set_offset(&lc, offset);
     315  		if (!rc && sizelimit)
     316  			rc = loopcxt_set_sizelimit(&lc, sizelimit);
     317  		if (!rc)
     318  			loopcxt_set_flags(&lc, lo_flags);
     319  		if (rc) {
     320  			DBG(LOOP, ul_debugobj(cxt, "failed to set loop attributes"));
     321  			goto done;
     322  		}
     323  
     324  		/* setup the device */
     325  		rc = loopcxt_setup_device(&lc);
     326  		if (!rc)
     327  			break;		/* success */
     328  
     329  		if (loopdev || rc != -EBUSY) {
     330  			DBG(LOOP, ul_debugobj(cxt, "failed to setup device"));
     331  			rc = -MNT_ERR_LOOPDEV;
     332  			goto done;
     333  		}
     334  		DBG(LOOP, ul_debugobj(cxt, "device stolen...trying again"));
     335  	} while (1);
     336  
     337  success:
     338  	if (!rc)
     339  		rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc));
     340  
     341  	if (!rc) {
     342  		if (loopopt && (reuse || loopcxt_is_autoclear(&lc))) {
     343  			/*
     344  			 * autoclear flag accepted by the kernel, don't store
     345  			 * the "loop=" option to utab.
     346  			 */
     347  			DBG(LOOP, ul_debugobj(cxt, "removing unnecessary loop= from utab"));
     348  			mnt_optlist_remove_opt(ol, loopopt);
     349  			loopopt = NULL;
     350  		}
     351  
     352  		if (!mnt_optlist_is_rdonly(ol) && loopcxt_is_readonly(&lc))
     353  			/*
     354  			 * mount planned read-write, but loopdev is read-only,
     355  			 * let's fix mount options...
     356  			 */
     357  			mnt_optlist_append_flags(ol, MS_RDONLY, cxt->map_linux);
     358  
     359  		/* we have to keep the device open until mount(1),
     360  		 * otherwise it will be auto-cleared by kernel
     361  		 */
     362  		hd->loopdev_fd = loopcxt_get_fd(&lc);
     363  		if (hd->loopdev_fd < 0) {
     364  			DBG(LOOP, ul_debugobj(cxt, "failed to get loopdev FD"));
     365  			rc = -errno;
     366  		} else
     367  			loopcxt_set_fd(&lc, -1, 0);
     368  	}
     369  done:
     370  	loopcxt_deinit(&lc);
     371  done_no_deinit:
     372  	return rc;
     373  }
     374  
     375  static int delete_loopdev(struct libmnt_context *cxt, struct hook_data *hd)
     376  {
     377  	const char *src;
     378  	int rc;
     379  
     380  	assert(cxt);
     381  	assert(cxt->fs);
     382  
     383  	src = mnt_fs_get_srcpath(cxt->fs);
     384  	if (!src)
     385  		return -EINVAL;
     386  
     387  	if (hd && hd->loopdev_fd > -1) {
     388  		close(hd->loopdev_fd);
     389  		hd->loopdev_fd = -1;
     390  	}
     391  
     392  	rc = loopdev_delete(src);	/* see lib/loopdev.c */
     393  
     394  	DBG(LOOP, ul_debugobj(cxt, "deleted [rc=%d]", rc));
     395  	return rc;
     396  }
     397  
     398  /* Now used by umount until context_umount.c will use hooks toosee  */
     399  int mnt_context_delete_loopdev(struct libmnt_context *cxt)
     400  {
     401  	return delete_loopdev(cxt, NULL);
     402  }
     403  
     404  static int is_loopdev_required(struct libmnt_context *cxt, struct libmnt_optlist *ol)
     405  {
     406  	const char *src, *type;
     407  	unsigned long flags = 0;
     408  
     409  	if (cxt->action != MNT_ACT_MOUNT)
     410  		return 0;
     411  	if (!cxt->fs)
     412  		return 0;
     413  	if (mnt_optlist_is_bind(ol)
     414  	    || mnt_optlist_is_move(ol)
     415  	    || mnt_context_propagation_only(cxt))
     416  		return 0;
     417  
     418  	src = mnt_fs_get_srcpath(cxt->fs);
     419  	if (!src)
     420  		return 0;		/* backing file not set */
     421  
     422  	/* userspace flags */
     423  	if (mnt_context_get_user_mflags(cxt, &flags))
     424  		return 0;
     425  
     426  	if (flags & (MNT_MS_LOOP | MNT_MS_OFFSET | MNT_MS_SIZELIMIT)) {
     427  		DBG(LOOP, ul_debugobj(cxt, "loopdev specific options detected"));
     428  		return 1;
     429  	}
     430  
     431  	/* Automatically create a loop device from a regular file if a
     432  	 * filesystem is not specified or the filesystem is known for libblkid
     433  	 * (these filesystems work with block devices only). The file size
     434  	 * should be at least 1KiB, otherwise we will create an empty loopdev with
     435  	 * no mountable filesystem...
     436  	 *
     437  	 * Note that there is no restriction (on kernel side) that would prevent a regular
     438  	 * file as a mount(2) source argument. A filesystem that is able to mount
     439  	 * regular files could be implemented.
     440  	 */
     441  	type = mnt_fs_get_fstype(cxt->fs);
     442  
     443  	if (mnt_fs_is_regularfs(cxt->fs) &&
     444  	    (!type || strcmp(type, "auto") == 0 || blkid_known_fstype(type))) {
     445  		struct stat st;
     446  
     447  		if (stat(src, &st) == 0 && S_ISREG(st.st_mode) &&
     448  		    st.st_size > 1024) {
     449  
     450  			DBG(LOOP, ul_debugobj(cxt, "automatically enabling loop= option"));
     451  			mnt_optlist_append_flags(ol, MNT_MS_LOOP, cxt->map_userspace);
     452  			return 1;
     453  		}
     454  	}
     455  
     456  	return 0;
     457  }
     458  
     459  /* call after mount(2) */
     460  static int hook_cleanup_loopdev(
     461  			struct libmnt_context *cxt,
     462  			const struct libmnt_hookset *hs __attribute__((__unused__)),
     463  			void *data)
     464  {
     465  	struct hook_data *hd = (struct hook_data *) data;
     466  
     467  	if (!hd || hd->loopdev_fd < 0)
     468  		return 0;
     469  
     470  	if (mnt_context_get_status(cxt) == 0) {
     471  		/*
     472  		 * mount(2) failed, delete loopdev
     473  		 */
     474  		delete_loopdev(cxt, hd);
     475  
     476  	} else {
     477  		/*
     478  		 * mount(2) success, close the device
     479  		 */
     480  		DBG(LOOP, ul_debugobj(cxt, "closing FD"));
     481  		close(hd->loopdev_fd);
     482  		hd->loopdev_fd = -1;
     483  	}
     484  
     485  	return 0;
     486  }
     487  
     488  /* call to prepare mount source */
     489  static int hook_prepare_loopdev(
     490                          struct libmnt_context *cxt,
     491                          const struct libmnt_hookset *hs,
     492                          void *data __attribute__((__unused__)))
     493  {
     494  	struct libmnt_optlist *ol;
     495  	struct hook_data *hd;
     496  	int rc;
     497  
     498  	assert(cxt);
     499  
     500  	ol = mnt_context_get_optlist(cxt);
     501  	if (!ol)
     502  		return -ENOMEM;
     503  	if (!is_loopdev_required(cxt, ol))
     504  		return 0;
     505  	hd = new_hook_data();
     506  	if (!hd)
     507  		return -ENOMEM;
     508  
     509  	rc = setup_loopdev(cxt, ol, hd);
     510  	if (!rc)
     511  		rc = mnt_context_append_hook(cxt, hs,
     512  				MNT_STAGE_MOUNT_POST,
     513  				hd, hook_cleanup_loopdev);
     514  	if (rc) {
     515  		delete_loopdev(cxt, hd);
     516  		free(hd);
     517  	}
     518  	return rc;
     519  }
     520  
     521  
     522  const struct libmnt_hookset hookset_loopdev =
     523  {
     524          .name = "__loopdev",
     525  
     526          .firststage = MNT_STAGE_PREP_SOURCE,
     527          .firstcall = hook_prepare_loopdev,
     528  
     529          .deinit = hookset_deinit
     530  };