CVE-2021-3996 (published 2022-08-23T20:15Z)

A logic error was found in the libmount library of util-linux in the function that allows an unprivileged user to unmount a FUSE filesystem. This flaw allows a local user on a vulnerable system to unmount other users' filesystems that are either world-writable themselves (like /tmp) or mounted in a world-writable directory. An attacker may use this flaw to cause a denial of service to applications that use the affected filesystems.

CVSS v3 base score: 5.5, MEDIUM (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-552
cwe_name: Files or Directories Accessible to External Parties
description: The product makes files or directories accessible to unauthorized actors, even though they should not be.
extended_description: 
	   Web servers, FTP servers, and similar servers may store a set of files underneath a "root" directory that is accessible to the server's users.  Applications may store sensitive files underneath this root without also using access control to limit which users may request those files, if any.  Alternately, an application might package multiple files or directories into an archive file (e.g., ZIP or tar), but the application might not exclude sensitive files that are underneath those directories.
	   In cloud technologies and containers, this weakness might present itself in the form of misconfigured storage accounts that can be read or written by a public or anonymous user.
	 
         

Fix information:
repo_url: https://github.com/util-linux/util-linux
commit_details: repo_url: https://github.com/util-linux/util-linux
author: Karel Zak
author_date: 2022-01-04 10:37:55+01:00
msg: libmount: remove support for deleted mount table entries

The "(deleted)" suffix has been originally used by kernel for deleted
mountpoints. Since kernel commit 9d4d65748a5ca26ea8650e50ba521295549bf4e3
(Dec 2014) kernel does not use this suffix for mount stuff in /proc at
all. Let's remove this support from libmount too.

Signed-off-by: Karel Zak <kzak@redhat.com>
repository: repo_url: https://github.com/util-linux/util-linux
repo_name: util-linux/util-linux
repo_language: C
owner: util-linux
file_changes: filename: libmount-sections.txt
change_type: ModificationType.MODIFY
diff: @@ -246,7 +246,6 @@ mnt_fs_get_userdata
 mnt_fs_get_user_options
 mnt_fs_get_vfs_options
 mnt_fs_get_vfs_options_all
-mnt_fs_is_deleted
 mnt_fs_is_kernel
 mnt_fs_is_netfs
 mnt_fs_is_pseudofs

programming_language: Shell
filename: fs.c
change_type: ModificationType.MODIFY
diff: @@ -651,17 +651,6 @@ int mnt_fs_is_regularfs(struct libmnt_fs *fs)
 		 || mnt_fs_is_swaparea(fs));
 }
 
-/**
- * mnt_fs_is_deleted:
- * @fs: filesystem
- *
- * Returns: 1 if the filesystem target is a marked as deleted by kernel
- */
-int mnt_fs_is_deleted(struct libmnt_fs *fs)
-{
-	return mnt_fs_get_flags(fs) & MNT_FS_DELETED;
-}
-
 /**
  * mnt_fs_get_fstype:
  * @fs: fstab/mtab/mountinfo entry pointer

programming_language: C
filename: libmount.h.in
change_type: ModificationType.MODIFY
diff: @@ -512,7 +512,6 @@ extern int mnt_fs_match_options(struct libmnt_fs *fs, const char *options);
 extern int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file);
 
 extern int mnt_fs_is_kernel(struct libmnt_fs *fs);
-extern int mnt_fs_is_deleted(struct libmnt_fs *fs);
 extern int mnt_fs_is_swaparea(struct libmnt_fs *fs);
 extern int mnt_fs_is_netfs(struct libmnt_fs *fs);
 extern int mnt_fs_is_pseudofs(struct libmnt_fs *fs);

programming_language: C
filename: libmount.sym
change_type: ModificationType.MODIFY
diff: @@ -365,5 +365,4 @@ MOUNT_2_37 {
 
 MOUNT_2_38 {
 	mnt_fs_is_regularfs;
-	mnt_fs_is_deleted;
 } MOUNT_2_37;

programming_language: SQL
filename: mountP.h
change_type: ModificationType.MODIFY
diff: @@ -228,7 +228,6 @@ struct libmnt_fs {
 #define MNT_FS_SWAP	(1 << 3) /* swap device */
 #define MNT_FS_KERNEL	(1 << 4) /* data from /proc/{mounts,self/mountinfo} */
 #define MNT_FS_MERGED	(1 << 5) /* already merged data from /run/mount/utab */
-#define MNT_FS_DELETED	(1 << 6) /* target path in mountinfo contains "(deleted)" */
 
 /*
  * mtab/fstab/mountinfo file

programming_language: C
filename: tab_parse.c
change_type: ModificationType.MODIFY
diff: @@ -227,13 +227,6 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, const char *s)
 		goto fail;
 	}
 
-	/* remove "\040(deleted)" suffix */
-	p = (char *) endswith(fs->target, PATH_DELETED_SUFFIX);
-	if (p && *p) {
-		*p = '\0';
-		fs->flags |= MNT_FS_DELETED;
-	}
-
 	s = skip_separator(s);
 
 	/* (6) vfs options (fs-independent) */

programming_language: C
filename: findmnt.c
change_type: ModificationType.MODIFY
diff: @@ -55,7 +55,6 @@
 enum {
 	COL_ACTION,
 	COL_AVAIL,
-	COL_DELETED,
 	COL_FREQ,
 	COL_FSROOT,
 	COL_FSTYPE,
@@ -103,7 +102,6 @@ struct colinfo {
 static struct colinfo infos[] = {
 	[COL_ACTION]       = { "ACTION",         10, SCOLS_FL_STRICTWIDTH, N_("action detected by --poll") },
 	[COL_AVAIL]        = { "AVAIL",           5, SCOLS_FL_RIGHT, N_("filesystem size available") },
-	[COL_DELETED]      = { "DELETED",         1, SCOLS_FL_RIGHT, N_("filesystem target marked as deleted") },
 	[COL_FREQ]         = { "FREQ",            1, SCOLS_FL_RIGHT, N_("dump(8) period in days [fstab only]") },
 	[COL_FSROOT]       = { "FSROOT",       0.25, SCOLS_FL_NOEXTREMES, N_("filesystem root") },
 	[COL_FSTYPE]       = { "FSTYPE",       0.10, SCOLS_FL_TRUNC, N_("filesystem type") },
@@ -677,9 +675,6 @@ static char *get_data(struct libmnt_fs *fs, int num)
 		if (!mnt_fs_is_kernel(fs))
 			xasprintf(&str, "%d", mnt_fs_get_passno(fs));
 		break;
-	case COL_DELETED:
-		str = xstrdup(mnt_fs_is_deleted(fs) ? "1" : "0");
-		break;
 	default:
 		break;
 	}
@@ -1033,9 +1028,6 @@ static int match_func(struct libmnt_fs *fs,
 			return rc;
 	}
 
-	if ((flags & FL_DELETED) && !mnt_fs_is_deleted(fs))
-		return rc;
-
 	return !rc;
 }
 
@@ -1304,7 +1296,6 @@ static void __attribute__((__noreturn__)) usage(void)
 	fputs(_(" -b, --bytes            print sizes in bytes rather than in human readable format\n"), out);
 	fputs(_(" -C, --nocanonicalize   don't canonicalize when comparing paths\n"), out);
 	fputs(_(" -c, --canonicalize     canonicalize printed paths\n"), out);
-	fputs(_("     --deleted          print filesystems with mountpoint marked as deleted\n"), out);
 	fputs(_(" -D, --df               imitate the output of df(1)\n"), out);
 	fputs(_(" -d, --direction <word> direction of search, 'forward' or 'backward'\n"), out);
 	fputs(_(" -e, --evaluate         convert tags (LABEL,UUID,PARTUUID,PARTLABEL) \n"
@@ -1373,8 +1364,7 @@ int main(int argc, char *argv[])
 		FINDMNT_OPT_PSEUDO,
 		FINDMNT_OPT_REAL,
 		FINDMNT_OPT_VFS_ALL,
-		FINDMNT_OPT_SHADOWED,
-		FINDMNT_OPT_DELETED,
+		FINDMNT_OPT_SHADOWED
 	};
 
 	static const struct option longopts[] = {
@@ -1382,7 +1372,6 @@ int main(int argc, char *argv[])
 		{ "ascii",	    no_argument,       NULL, 'a'		 },
 		{ "bytes",	    no_argument,       NULL, 'b'		 },
 		{ "canonicalize",   no_argument,       NULL, 'c'		 },
-		{ "deleted",        no_argument,       NULL, FINDMNT_OPT_DELETED },
 		{ "direction",	    required_argument, NULL, 'd'		 },
 		{ "df",		    no_argument,       NULL, 'D'		 },
 		{ "evaluate",	    no_argument,       NULL, 'e'		 },
@@ -1601,9 +1590,6 @@ int main(int argc, char *argv[])
 		case FINDMNT_OPT_SHADOWED:
 			flags |= FL_SHADOWED;
 			break;
-		case FINDMNT_OPT_DELETED:
-			flags |= FL_DELETED;
-			break;
 		case 'h':
 			usage();
 		case 'V':
@@ -1776,9 +1762,6 @@ int main(int argc, char *argv[])
 			case COL_TID:
 				scols_column_set_json_type(cl, SCOLS_JSON_NUMBER);
 				break;
-			case COL_DELETED:
-				scols_column_set_json_type(cl, SCOLS_JSON_BOOLEAN);
-				break;
 			default:
 				if (fl & SCOLS_FL_WRAP)
 					scols_column_set_json_type(cl, SCOLS_JSON_ARRAY_STRING);

programming_language: C