fs/ext: Fix encoding for surrogate pairs #535
Dismiss Review
Are you sure you want to dismiss this review?
Labels
Clear labels
AI
Eolite
FS
Good First PR
GSoC
HardwareTested
HLL
Influence/Settings
Influence/Text/TYPO
IRCC
Lang/C
Lang/FASM
Pay for the code
Subsystem/API
Subsystem/Audio
Subsystem/Graphics
Subsystem/IPC and events
Subsystem/Memory
Subsystem/Network
Subsystem/Services(daemon)
Subsystem/Taskmanager
Subsystem/VFS
Subsystem/Window
Category
Applications
Category
Drivers
Category
General
Category
Kernel
Category
Libraries
The issue is suitable to beginners
This issue or PR in the Google Source of Code program
Kind
Breaking
Breaking change that won't be backward compatible
Kind
Bug
Something is not working
Kind
Build
Kind
Documentation
Documentation changes
Kind
Enhancement
Improve existing functionality
Kind
Feature
New functionality
Kind
Security
This is security issue
Kind
Testing
Issue or pull request related to testing
Paid task
PR
Conflicts
PR conflicts with main
PR
Dependent
This PR is dependent on another PR
Priority
Critical
1
The priority is critical
Priority
High
2
The priority is high
Priority
Low
4
The priority is low
Priority
Medium
3
The priority is medium
PR
Ready to merge
Pull request is ready for merge
PR
Request changes
Changes requested in pull request
PR
Review required
Reviewed
Confirmed
Issue has been confirmed
Reviewed
Duplicate
This issue or pull request already exists
Reviewed
Invalid
Invalid issue
Reviewed
Won't Fix
This issue won't be fixed
Status
Abandoned
Somebody has started to work on this but abandoned work
Status
Blocked
Something is blocking this issue or pull request
Status
Need More Info
Feedback is required to reproduce issue or to continue work
infinity service, audio drivers, midi, speacker, audio programs
vesa, vga, framebuffer, cursors, blitter, and video drivers
pipes, signals, events, shared memory
virt and phys memory allocators, malloc and other
userspace and kernel(for example: serial) services
process, threads, run apps, scheduler
drivers from filesystem, fs api, blkdev, programs that work with the file system
windows, skins, buttons, mouse and keyboard code for windows (not the base code)
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: KolibriOS/kolibrios#535
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Replaced
utf8to16calls withunicode.utfX.encode/decode.Created umka test 87 similar to xfs' t011
Logic looks correct, but I suspect one real problem - infinite loop on non-UTF-8 / malformed names.
unicode.utf8.decode's.errorpath doesn't advanceesior decrementecx, and the loop only checksecx:ext filenames are arbitrary bytes (not guaranteed UTF-8), so a non-UTF-8 name hangs the kernel. The old
cmp esi, ecxloop was bounded. Same pattern exists inxfs.asm, so the real fix is inunicode.utf8.decode(guarantee forward progress on error).Minor - inconsistent label names:
.utf16_loop_nextvs.utf16_no_highfor the same construct.f20d813657to1c0525b8f71c0525b8f7tof20d813657f20d813657to6868dd2019@Burer Please let me know if that's what you meant, and if there is anything else.
@Matou1306
The hang fix and label unification look good. But making
.erroradvance without sanitizingeaxturns the old hang into an out-of-bounds write in the UTF-16 path.OOB write**. On error,
unicode.utf8.decodeleaves the partial codepoint ineax, which can be>= 0x10000(an error after theshl eax, 6stages in.read4) while consuming only 1 byte.unicode.utf16.encodethen emits a 2-word surrogate pair for that garbage. ext names are arbitrary bytes (not guaranteed UTF-8), so a crafted name likeF4 90repeated yields ~1.5 UTF-16 units/byte - a 254-byte name writes ~380 units (~760 bytes) into the 520-byte (260-unit) name field, overflowing it in bothext_ReadFolderandext_GetFileInfo. Valid UTF-8 is unaffected (<= 1unit/byte). The samedecodeis shared withxfs.asm, so xfs has it too.Fix at the root so each consumed byte yields exactly one unit:
This also makes the cp866 path emit a proper replacement instead of a garbage byte.
Also, a few minor problems remains, just for your info:
Lone surrogate.
decodeaccepts 3-byte sequences encoding the surrogate range U+D800-U+DFFF (e.g.ED A0 80);unicode.utf16.encodereturns those unchanged, emitting a lone surrogate (invalid UTF-16). One word, no overflow. The fix above doesn't cover it (decode treats it as success) - either reject surrogates indecodeor emit a replacement inutf16.encode's.error.Out of scope.
fat,ntfs,iso9660,exfat,fs_lfn,gui/font,taskmanstill use the oldutf8to16, so they keep the supplementary-char limitation this PR fixes for ext. Would be nice to fix them as well in future.@Burer thanks, please take a look at this.
Btw the new build system looks awesome! I noticed it built significantly faster now.
@Matou1306
The error hardening looks correct now, thank you.
One real bug remains, and it's the case this PR targets:
unicode.utf16.encode.write2swaps the high/low 10 bits of the surrogate pair.After
shl eax,6/shr ax,6the low word holds L (bottom 10 bits) and the high word holds H (top 10). Theorthen pairs the lead base0xD800with L and the trail base0xDC00with H. It must be lead =0xD800+H, trail =0xDC00+L. The code emits the low word first (stosw):D800 DC01D801 DC00(= U+10400)D83D DE00DA00 DC3D(= U+9003D)(Only H==L codepoints like U+10000 / U+10FFFF come out right by coincidence.) Every supplementary-plane name on the UTF-16 path -
ext_ReadFolder,ext_GetFileInfo([edx+4]==2), andxfs.asmvia the shared encoder - decodes to the wrong character. The size is correct (2 units), so no overflow - value bug only. The math is pre-existing, but this is the first PR to actually write both words.Fix should be simple, but please, double-check this before applying:
Verified by replicating the exact bit-ops: the current code is wrong for U+10001 / U+10400 / U+1F600; with
rorall of U+10000 / 10001 / 10400 / 1F600 / 10FFFF match the reference values.Minor: the empty-input path now falls through to
.donewitheaxunset - correct to avoid thedec ecxunderflow, but a zero-length name (corrupt image) then writes one garbage unit. Settingeax, 0xFFFDthere too, or guardingecx > 0in the caller, would make it fully defensive.@Burer I just applied the change, thanks for spotting it! I couldn't notice it because umka tests were already popping unreadable characters because every line showed different encodings, so I didn't check whether the "unreadable" character was correct or not.
As for the suggestion in the end, extfs already guards ecx. Given it is already something that shouldn't happen and the result won't cause panic, I would lean more towards leaving the responsibility for the caller. Unless you think otherwise for sure.
ps: I realized building is failing for some reason, tup works fine locally idk why is that happening?
75dca8e75eto096227e3cc@Matou1306
Looks okay after rebase on fresh main!
096227e3ccto68d5ac736f