pkgsrc-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

pkg/57496: fuse-exfat: broken on wedges: 10GB wedge seen as 4.7TB breaking all exfat commands



>Number:         57496
>Category:       pkg
>Synopsis:       fuse-exfat: broken on wedges: 10GB wedge seen as 4.7TB breaking all exfat commands
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    pkg-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Jul 01 14:40:00 +0000 2023
>Originator:     Henryk Paluch
>Release:        9.3-RELEASE + pkgsrc-2023Q2
>Organization:
N/A
>Environment:
NetBSD localhost 9.3 NetBSD 9.3 (GENERIC) #0: Thu Aug  4 15:30:37 UTC 2022  mkrepro%mkrepro.NetBSD.org@localhost:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
When attempting to format and use exFAT partition on wedge (GPT in my case) - all utilities (mkexfatfs, exfatfsck, mount.exfat-fuse) will see such wedge with ridiculous incorrect size (4.7TB instead of 10GB in my case) and thus choking on any useful operation.

The problem is bug in libexfat/io.c that treats wedge as disk (or disklabel) and thus computing incorrect device size for wedge.


>How-To-Repeat:
1. Create GPT partition for exFAT, example (you need to customize it to your environment):

gpt add -a 4k -t windows -l exfat1 -b 43057216 ld0

(you have to replace 43057216 with your first free block on GPT table and replace "ld0" with your disk device).
Please note that exFAT minimum size is 1GB or so.

2. Check new wedge corresponding to new exFAT partition in GPT table (replace "ld0" with your disk name).

dkctl ld0 listwedges
  
  /dev/rld0: 3 wedges:
  ...
  dk2: exfat1, 19857304 blocks at 43057216, type: ntfs

(listed only new wedge for exfat). In my case the wedge has size 10GB.

3. Install fuse-exfat package:

pkgin in fuse-exfat

In my case package version is fuse-exfat-1.3.0nb1

4. Format new wedge as exFAT (please note that libexfat works only with Block device - it will internally replace it with Raw device):

mkexfatfs -n EXFAT1 /dev/dk2

5. There is no error reported, but the formatted filesystem has totally wrong size. You can verify this claim two ways:

a) using exfatfsck, for example:

exfatfsck -n /dev/dk2

exfatfsck 1.3.0
Checking file system on /dev/dk2.
File system version           1.0
Sector size                 512 bytes
Cluster size                128 KB
Volume size                4848 GB
Used space                  368 MB
Available space            4848 GB
Totally 2 directories and 21 files.
File system checking finished. No errors found.

NOTICE wrong "Volume size" and "Available space" size (4848 GB = 4.8TB) - it should be just 10GB.

b) you can try to mount this filesystem and issue `df` command:

mkdir -p /mnt/exfat
mount.exfat-fuse /dev/dk2 /mnt/exfat/

df -h /mnt/exfat

Filesystem         Size       Used      Avail %Cap Mounted on
/dev/puffs         4.7T       157M       4.7T   0% /mnt/exfat

Notice totally bogus Size (again around 4.8TB) and Avail - if you attempt to write lot of data of filesystem and will be completely screwed...


>Fix:
I created this patch (for already patched pkgsrc-2023Q2), that fixes problem for me. However I'm new to NetBSD and I need some mentor to review this patch and some volunteer to test it (with the risk of data loss):

--- libexfat/io.c.orig	2023-07-01 15:28:46.089450095 +0200
+++ libexfat/io.c	2023-07-01 16:11:06.598265322 +0200
@@ -36,7 +36,9 @@
 #include <sys/dkio.h>
 #include <sys/ioctl.h>
 #elif defined(__NetBSD__)
+#include <sys/disk.h>
 #include <sys/param.h>
+#include <sys/ioctl.h>
 #include <util.h>
 #include "nbpartutil.h"
 #elif __linux__
@@ -239,11 +241,40 @@ struct exfat_dev* exfat_open(const char*
 			char device[MAXPATHLEN];
 			u_int secsize;
 			off_t dksize;
+			int err;
+			const char *WEDGE_PREFIX = "/dev/rdk";
 
 			/* mkexfatfs can only use the block device, but */
 			/* getdisksize() needs the raw device name      */
-			getdiskrawname(device, sizeof(device), spec);
-			getdisksize(device, &secsize, &dksize);
+			if (getdiskrawname(device, sizeof(device), spec)==NULL){
+				exfat_error("getdiskrawname('%s'): %s",spec,strerror(errno));
+				return NULL;
+			}
+
+			err = getdisksize(device, &secsize, &dksize);
+			if (err){
+				exfat_error("getdisksize('%s'): error=%d",device,err);
+				return NULL;
+			}
+
+			/* NOTE: dksize is incorrect for wedges - we have to use dedicated ioctl */
+			if (strncmp(device,WEDGE_PREFIX,strlen(WEDGE_PREFIX)) == 0){
+				int fd;
+				struct dkwedge_info dkw;
+				if ((fd = open_ro(device)) == -1){
+					exfat_error("wedge: open_ro('%s'): %s",
+							device,strerror(errno));
+					return NULL;
+				}
+				if (ioctl(fd, DIOCGWEDGEINFO, &dkw) < 0) {
+					exfat_error("wedge: ioctl('%s',DIOCGWEDGEINFO): %s",
+							device,strerror(errno));
+					close(fd);
+					return NULL;
+				}
+				close(fd);
+				dksize = dkw.dkw_size;
+			}
 			dev->size = secsize * dksize;
 		}
 		if (dev->size <= 0) {


Home | Main Index | Thread Index | Old Index