Bug ID | 1210266 |
---|---|
Summary | fuse-exfat allows creation of Unicode name that will later crash it with abort() |
Classification | openSUSE |
Product | openSUSE Distribution |
Version | Leap 15.4 |
Hardware | Other |
OS | Other |
Status | NEW |
Severity | Normal |
Priority | P5 - None |
Component | Basesystem |
Assignee | screening-team-bugs@suse.de |
Reporter | hpaluch@seznam.cz |
QA Contact | qa-bugs@suse.de |
Found By | --- |
Blocker | --- |
The fuse-exfat that is used to acces exFAT filesystem allows to create semi-invalid unicode names that will later crash it (leaving mounted filesystem stuck) everytime such file (or directory) name accessed. The error messages are: ERROR: illegal UTF-16 sequence. BUG: failed to convert name to UTF-8. Aborted Since that moment whole exFat filesytem is stuck because the exFAT FUSE backend died and the only workaround is to force umount it with "umount -f /mountpoint) and mount it again. However it will again crash everytime such file or directory name is accessed. Tested on openSUSE LEAP 15.4 with these RPMS: $ rpm -q exfatprogs fuse-exfat libfuse2 exfatprogs-1.0.4-150300.3.6.1.x86_64 fuse-exfat-1.3.0-bp154.1.20.x86_64 libfuse2-2.9.7-3.3.1.x86_64 How to reproduce: 1. Ensure that required RPMs are installed: sudo zypper in exfatprogs fuse-exfat libfuse2 2. Run these commands on 1st terminal: sudo mkdir -p /mnt/test rm -f ~/exfat.img cd truncate -s 128M ~/exfat.img /usr/sbin/mkfs.exfat -L EXFAT_BUG ~/exfat.img loop_dev=`sudo /sbin/losetup -f --show ~/exfat.img` sudo /usr/sbin/mount.exfat -d $loop_dev /mnt/test 3. Last command (fuse mount of exfat) should produce message like: USE exfat 1.3.0 FUSE library version: 2.9.7 nullpath_ok: 0 4. Now open another terminal and create file with semi-invalid UTF-8 that will be converted to specific 16-bit Unicode filename: sudo mkdir /mnt/test/bad`echo -ne '\xed\xaa\xad'` 5. Unmount filesystem to force flush of all caches of FUSE process: sudo umount /mnt/test 6. Now back on 1st terminal mount again exFat filesystem in debug mode sudo /usr/sbin/mount.exfat -d $loop_dev /mnt/test 7. On second terminal issue this trivial command: ls -l /mnt/test/ ls: reading directory '/mnt/test/': Software caused connection abort 8. Notice that above ls command failed with error "Software caused connection abort" 9. However when you switch back to 1st terminal you will see it is much worse because the whole FUSE process mount.exfat was aborted with these messages: readdir[0] from 0 ERROR: illegal UTF-16 sequence. BUG: failed to convert name to UTF-8. Aborted 10. Now the mounted filesystem is completely stuck (because FUSE backend crashed). And the only thing we can do is to force unmount it: sudo umount -f /mnt/test Now we are in trouble: we have exFAT filesystem where any access to specific filename will crash FUSE backend and making it unusable till force unmount and mount... How to get backgtrace: 1. install those additional packages using: sudo zypper in gdb sudo zypper --plus-content debug in exfatprogs-debuginfo \ fuse-exfat-debuginfo libfuse2-debuginfo 2. This time run FUSE backend in GDB using these two commands: sudo gdb /sbin/mount.exfat-fuse (gdb) run -d -o ro /dev/loop0 /mnt/test/ 3. On second terminal trigger crash: ls -l /mnt/test/ 4. In gdb there will be catched abort and you can run bt to see backgtrace: readdir[0] from 0 ERROR: illegal UTF-16 sequence. BUG: failed to convert name to UTF-8. Program received signal SIGABRT, Aborted. 0x00007ffff7bb4c6b in raise () from /lib64/libc.so.6 (gdb) bt #0 0x00007ffff7bb4c6b in raise () from /lib64/libc.so.6 #1 0x00007ffff7bb6305 in abort () from /lib64/libc.so.6 #2 0x0000555555403e89 in exfat_bug (format=format@entry=0x5555554096a8 "failed to convert name to UTF-8") at log.c:58 #3 0x0000555555408054 in exfat_get_name (node=node@entry=0x55555560de40, buffer=buffer@entry=0x7fffffffe2f0 "bad\367\377\177") at utils.c:53 #4 0x0000555555402363 in fuse_exfat_readdir (path=<optimized out>, buffer=0x55555560e420, filler=0x7ffff7d8cc60 <fill_dir>, offset=<optimized out>, fi=<optimized out>) at main.c:131 #5 0x00007ffff7d92287 in fuse_fs_readdir (fs=0x55555560e690, path=0x555555631350 "/", buf=0x55555560e420, filler=0x7ffff7d8cc60 <fill_dir>, off=0, fi=0x7fffffffe6c0) at fuse.c:2009 #6 0x00007ffff7d92448 in readdir_fill (fi=0x7fffffffe6c0, dh=0x55555560e420, off=0, size=4096, ino=1, req=0x555555631690, f=0x55555560e530) at fuse.c:3467 #7 fuse_lib_readdir (req=0x555555631690, ino=1, size=4096, off=0, llfi=<optimized out>) at fuse.c:3493 #8 0x00007ffff7d98f72 in do_readdir (req=<optimized out>, nodeid=<optimized out>, inarg=<optimized out>) at fuse_lowlevel.c:1390 #9 0x00007ffff7d9a101 in fuse_ll_process_buf (data=0x555555610e90, buf=0x7fffffffe940, ch=<optimized out>) at fuse_lowlevel.c:2443 #10 0x00007ffff7d969af in fuse_session_loop (se=se@entry=0x55555560e850) at fuse_loop.c:40 #11 0x00007ffff7d8ecd8 in fuse_loop (f=f@entry=0x55555560e530) at fuse.c:4322 #12 0x00007ffff7d9f24c in fuse_main_common (argc=argc@entry=5, argv=argv@entry=0x7fffffffeac0, op=op@entry=0x55555560c1e0 <fuse_exfat_ops>, op_size=op_size@entry=360, user_data=user_data@entry=0x0, compat=compat@entry=25) at helper.c:371 #13 0x00007ffff7d9f2fe in fuse_main_real_compat25 (argc=argc@entry=5, argv=argv@entry=0x7fffffffeac0, --Type <RET> for more, q to quit, c to continue without paging-- op=op@entry=0x55555560c1e0 <fuse_exfat_ops>, op_size=op_size@entry=360) at helper.c:476 #14 0x0000555555401d43 in fuse_exfat_main (mount_point=0x7fffffffee90 "/mnt/test/", mount_options=0x55555560e0a0 "allow_other,big_writes,blkdev,default_permissions,debug,fsname=/dev/loop0,ro,blksize=4096") at main.c:511 #15 main (argc=<optimized out>, argv=<optimized out>) at main.c:603 5. To see details on problematic Unicode filename you can try this in GDB: (gdb) frame level 3 (gdb) print node->name $1 = {{__u16 = 98}, {__u16 = 97}, {__u16 = 100}, {__u16 = 55981}, {__u16 = 0} <repeats 252 times>} (gdb) x/8xh node->name 0x55555560de98: 0x0062 0x0061 0x0064 0xdaad 0x0000 0x0000 0x0000 0x0000 The problematic 16-bit Unicode is 0xdaad (byte sequence on LE machines is reverse - 0xad, 0xda) Please note that this command will not help you: sudo /usr/sbin/fsck.exfat /dev/LOOP_DEVICE Because it does not validate Unicode names in any way (it will report no problem at all). What's the cause: * main problem is that the UTF-8 -> Widechar -> Unicode 16 LE conversion is less strict than Unicode 16 LE -> Widechar -> UTF-8 conversion * it is the reason why we can create file (without error) that will later abort() backend process on every access. The question is how to properly fix that situation? If we make even UTF-8 -> Unicode path as strict as reverse path the end-user may still have unusable filesystem. How I encountered this bug? I copied old FAT16 USB pendrive to new exFAT HDD. The FAT16 used incorrect encodings (which is very _easy_). All files were copied to exFAT target and seemed to work, only later I found that on every eaccess of exFAT partition will crash FUSE backend...