From 74a4705a993ce475d95c1c20d0cc4eb740b0c933 Mon Sep 17 00:00:00 2001
From: Stanislav Brabec <sbrabec@suse.cz>
Date: Thu, 14 Jul 2016 15:29:09 +0200
Subject: [PATCH 4/20] Add sizelimit to internal API

Fully safe checks of loop device need to check sizelimit. To prevent need of two
nearly equal functions, introduce sizelimit parameter to several internal
functions:
loopdev_is_used()
loopdev_find_by_backing_file()
loopcxt_is_used()
loopcxt_find_by_backing_file()

If sizelimit is zero, fall back to the old behavior (ignoring of sizelimit).

Signed-off-by: Stanislav Brabec <sbrabec@suse.cz>
---
 include/loopdev.h              |  8 +++++---
 lib/ismounted.c                |  2 +-
 lib/loopdev.c                  | 26 +++++++++++++++++++-------
 libmount/src/context_loopdev.c |  6 +++---
 libmount/src/context_umount.c  |  2 +-
 libmount/src/tab.c             |  2 +-
 sys-utils/losetup.c            |  8 ++++----
 7 files changed, 34 insertions(+), 20 deletions(-)

Index: util-linux-2.25/include/loopdev.h
===================================================================
--- util-linux-2.25.orig/include/loopdev.h
+++ util-linux-2.25/include/loopdev.h
@@ -132,9 +132,9 @@ extern int loopdev_is_autoclear(const ch
 
 extern char *loopdev_get_backing_file(const char *device);
 extern int loopdev_is_used(const char *device, const char *filename,
-			   uint64_t offset, int flags);
+			   uint64_t offset, uint64_t sizelimit, int flags);
 extern char *loopdev_find_by_backing_file(const char *filename,
-					  uint64_t offset, int flags);
+				uint64_t offset, uint64_t sizelimit, int flags);
 extern int loopcxt_find_unused(struct loopdev_cxt *lc);
 extern int loopdev_delete(const char *device);
 extern int loopdev_count_by_backing_file(const char *filename, char **loopdev);
@@ -184,12 +184,14 @@ extern int loopcxt_is_readonly(struct lo
 extern int loopcxt_is_partscan(struct loopdev_cxt *lc);
 extern int loopcxt_find_by_backing_file(struct loopdev_cxt *lc,
 				const char *filename,
-                                uint64_t offset, int flags);
+				uint64_t offset, uint64_t sizelimit,
+				int flags);
 
 extern int loopcxt_is_used(struct loopdev_cxt *lc,
                     struct stat *st,
                     const char *backing_file,
                     uint64_t offset,
+                    uint64_t sizelimit,
                     int flags);
 
 #endif /* UTIL_LINUX_LOOPDEV_H */
Index: util-linux-2.25/lib/ismounted.c
===================================================================
--- util-linux-2.25.orig/lib/ismounted.c
+++ util-linux-2.25/lib/ismounted.c
@@ -80,7 +80,7 @@ static int check_mntent_file(const char
 			/* maybe the file is loopdev backing file */
 			if (file_dev
 			    && major(st_buf.st_rdev) == LOOPDEV_MAJOR
-			    && loopdev_is_used(mnt->mnt_fsname, file, 0, 0))
+			    && loopdev_is_used(mnt->mnt_fsname, file, 0, 0, 0))
 				break;
 #endif /* __linux__ */
 #endif	/* __GNU__ */
Index: util-linux-2.25/lib/loopdev.c
===================================================================
--- util-linux-2.25.orig/lib/loopdev.c
+++ util-linux-2.25/lib/loopdev.c
@@ -970,12 +970,15 @@ int loopcxt_is_readonly(struct loopdev_c
  * @backing_file: filename
  * @offset: offset
  * @flags: LOOPDEV_FL_OFFSET if @offset should not be ignored
+ * @flags: LOOPDEV_FL_SIZELIMIT if @sizelimit should not be ignored
  *
  * Returns 1 if the current @lc loopdev is associated with the given backing
  * file. Note that the preferred way is to use devno and inode number rather
  * than filename. The @backing_file filename is poor solution usable in case
  * that you don't have rights to call stat().
  *
+ * LOOPDEV_FL_SIZELIMIT requires LOOPDEV_FL_OFFSET being set as well.
+ *
  * Don't forget that old kernels provide very restricted (in size) backing
  * filename by LOOP_GET_STAT64 ioctl only.
  */
@@ -983,6 +986,7 @@ int loopcxt_is_used(struct loopdev_cxt *
 		    struct stat *st,
 		    const char *backing_file,
 		    uint64_t offset,
+		    uint64_t sizelimit,
 		    int flags)
 {
 	ino_t ino;
@@ -1020,7 +1024,15 @@ found:
 	if (flags & LOOPDEV_FL_OFFSET) {
 		uint64_t off;
 
-		return loopcxt_get_offset(lc, &off) == 0 && off == offset;
+		int rc = loopcxt_get_offset(lc, &off) == 0 && off == offset;
+
+		if (rc && flags & LOOPDEV_FL_SIZELIMIT) {
+			uint64_t sz;
+
+			return loopcxt_get_sizelimit(lc, &sz) == 0 && sz == sizelimit;
+		}
+		else
+			return rc;
 	}
 	return 1;
 }
@@ -1451,7 +1463,7 @@ char *loopdev_get_backing_file(const cha
  * Returns: TRUE/FALSE
  */
 int loopdev_is_used(const char *device, const char *filename,
-		    uint64_t offset, int flags)
+		    uint64_t offset, uint64_t sizelimit, int flags)
 {
 	struct loopdev_cxt lc;
 	struct stat st;
@@ -1467,7 +1479,7 @@ int loopdev_is_used(const char *device,
 		return rc;
 
 	rc = !stat(filename, &st);
-	rc = loopcxt_is_used(&lc, rc ? &st : NULL, filename, offset, flags);
+	rc = loopcxt_is_used(&lc, rc ? &st : NULL, filename, offset, sizelimit, flags);
 
 	loopcxt_deinit(&lc);
 	return rc;
@@ -1494,7 +1506,7 @@ int loopdev_delete(const char *device)
  * Returns: 0 = success, < 0 error, 1 not found
  */
 int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename,
-				 uint64_t offset, int flags)
+				 uint64_t offset, uint64_t sizelimit, int flags)
 {
 	int rc, hasst;
 	struct stat st;
@@ -1511,7 +1523,7 @@ int loopcxt_find_by_backing_file(struct
 	while ((rc = loopcxt_next(lc)) == 0) {
 
 		if (loopcxt_is_used(lc, hasst ? &st : NULL,
-					filename, offset, flags))
+				    filename, offset, sizelimit, flags))
 			break;
 	}
 
@@ -1522,7 +1534,7 @@ int loopcxt_find_by_backing_file(struct
 /*
  * Returns allocated string with device name
  */
-char *loopdev_find_by_backing_file(const char *filename, uint64_t offset, int flags)
+char *loopdev_find_by_backing_file(const char *filename, uint64_t offset, uint64_t sizelimit, int flags)
 {
 	struct loopdev_cxt lc;
 	char *res = NULL;
@@ -1532,7 +1544,7 @@ char *loopdev_find_by_backing_file(const
 
 	if (loopcxt_init(&lc, 0))
 		return NULL;
-	if (loopcxt_find_by_backing_file(&lc, filename, offset, flags) == 0)
+	if (loopcxt_find_by_backing_file(&lc, filename, offset, sizelimit, flags) == 0)
 		res = loopcxt_strdup_device(&lc);
 	loopcxt_deinit(&lc);
 
Index: util-linux-2.25/libmount/src/context_loopdev.c
===================================================================
--- util-linux-2.25.orig/libmount/src/context_loopdev.c
+++ util-linux-2.25/libmount/src/context_loopdev.c
@@ -119,13 +119,13 @@ is_mounted_same_loopfile(struct libmnt_c
 		rc = 0;
 
 		if (strncmp(src, "/dev/loop", 9) == 0) {
-			rc = loopdev_is_used((char *) src, bf, offset, LOOPDEV_FL_OFFSET);
+			rc = loopdev_is_used((char *) src, bf, offset, 0, LOOPDEV_FL_OFFSET);
 
 		} else if (opts && (cxt->user_mountflags & MNT_MS_LOOP) &&
 		    mnt_optstr_get_option(opts, "loop", &val, &len) == 0 && val) {
 
 			val = strndup(val, len);
-			rc = loopdev_is_used((char *) val, bf, offset, LOOPDEV_FL_OFFSET);
+			rc = loopdev_is_used((char *) val, bf, offset, 0, LOOPDEV_FL_OFFSET);
 			free(val);
 		}
 	}
@@ -227,7 +227,7 @@ int mnt_context_setup_loopdev(struct lib
 	if (rc)
 		goto done_no_deinit;
 	if (backing_file && !(loopcxt_find_by_backing_file(&lc,
-			backing_file, offset, LOOPDEV_FL_OFFSET))) {
+			backing_file, offset, sizelimit, LOOPDEV_FL_OFFSET))) {
 		DBG(CXT, ul_debugobj(cxt, "using existing loop device %s",
 					loopcxt_get_device(&lc)));
 		/* Once a loop is initialized RO, there is no way to safely
Index: util-linux-2.25/libmount/src/context_umount.c
===================================================================
--- util-linux-2.25.orig/libmount/src/context_umount.c
+++ util-linux-2.25/libmount/src/context_umount.c
@@ -344,7 +344,7 @@ static int is_associated_fs(const char *
 			return 0;
 	}
 
-	return loopdev_is_used(devname, src, offset, flags);
+	return loopdev_is_used(devname, src, offset, 0, flags);
 }
 
 static int prepare_helper_from_options(struct libmnt_context *cxt,
Index: util-linux-2.25/libmount/src/tab.c
===================================================================
--- util-linux-2.25.orig/libmount/src/tab.c
+++ util-linux-2.25/libmount/src/tab.c
@@ -1621,7 +1621,7 @@ int mnt_table_is_fs_mounted(struct libmn
 
  			DBG(FS, ul_debugobj(fs, "checking for loop: src=%s", mnt_fs_get_srcpath(fs)));
 
-			if (!loopdev_is_used(mnt_fs_get_srcpath(fs), src, offset, flags))
+			if (!loopdev_is_used(mnt_fs_get_srcpath(fs), src, offset, 0, flags))
 				continue;
 
 			DBG(FS, ul_debugobj(fs, "used loop"));
Index: util-linux-2.25/sys-utils/losetup.c
===================================================================
--- util-linux-2.25.orig/sys-utils/losetup.c
+++ util-linux-2.25/sys-utils/losetup.c
@@ -172,10 +172,10 @@ static int show_all_loops(struct loopdev
 			int used;
 			const char *bf = cn_file ? cn_file : file;
 
-			used = loopcxt_is_used(lc, st, bf, offset, flags);
+			used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
 			if (!used && !cn_file) {
 				bf = cn_file = canonicalize_path(file);
-				used = loopcxt_is_used(lc, st, bf, offset, flags);
+				used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
 			}
 			if (!used)
 				continue;
@@ -330,10 +330,10 @@ static int show_table(struct loopdev_cxt
 				int used;
 				const char *bf = cn_file ? cn_file : file;
 
-				used = loopcxt_is_used(lc, st, bf, offset, flags);
+				used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
 				if (!used && !cn_file) {
 					bf = cn_file = canonicalize_path(file);
-					used = loopcxt_is_used(lc, st, bf, offset, flags);
+					used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
 				}
 				if (!used)
 					continue;
