aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-22 17:12:25 +0200
committeruser <user@clank>2026-09-22 17:12:25 +0200
commita7a9cfdfa6b25101ae13a87abaddce0e736c7fd1 (patch)
treeb21102fac37210abfecc497bed8619892abc39e6 /src
parentusr: grep, more, cp, nc - and make pollcon pump the link (diff)
downloadgbos-a7a9cfdfa6b25101ae13a87abaddce0e736c7fd1.tar.gz
gbos-a7a9cfdfa6b25101ae13a87abaddce0e736c7fd1.tar.xz
gbos-a7a9cfdfa6b25101ae13a87abaddce0e736c7fd1.zip
fs: bounds-check direct blocks - a file over 2 KiB ate the next inode
sys_getb/sys_putb indexed inode.blocks[pos/256] with no limit at all, so a file that grew past its pointers just kept walking: first through the 4 unused bytes at the tail of the 16-byte inode, then straight into the NEXT inode, reading its type/nlink/size as block numbers. It hides well. Reads and writes alias identically, so a big file can be written and read back byte-for-byte and look fine - until something else touches the neighbouring inode, after which the tail of the file is garbage from whatever block those bytes now name. Found by serving a 7 KB file over httpd: corruption began at exactly offset 3072, and only sometimes. - NDIRECT 8 -> 12: bytes 4..15 are all block pointers now, which is what the runaway indexing was already doing by accident. Files go to 3 KiB, no on-disk layout change, no format bump. - getb past the last direct block reports EOF; putb drops the byte like a full disk. A capped file beats a corrupted neighbour. count 250 > big (7142 bytes) now stops at 3072 and its neighbours survive.
Diffstat (limited to 'src')
-rw-r--r--src/fs.asm10
1 files changed, 10 insertions, 0 deletions
diff --git a/src/fs.asm b/src/fs.asm
index adc04fb..9aeaeb7 100644
--- a/src/fs.asm
+++ b/src/fs.asm
@@ -833,6 +833,11 @@ sys_getb::
ld a, d
sbc b
jr nc, .eof ; pos >= size
+ ld a, d ; blkidx = pos/256
+ cp NDIRECT
+ jr nc, .eof ; past the last direct block: EOF, never index
+ ; off the end of the inode (that reads the
+ ; NEXT inode's fields as block numbers)
; data block = inode.blocks[pos/256 = D]
ld a, [wFsInode]
call inode_ptr
@@ -904,6 +909,11 @@ sys_putb::
ld e, a
ld a, [hl]
ld d, a ; DE = pos
+ ld a, d ; blkidx = pos/256
+ cp NDIRECT
+ jr nc, .done ; file is at its maximum size: drop the byte,
+ ; like a full disk. Growing past the inode's
+ ; pointers used to overwrite the next inode.
; ensure inode.blocks[pos/256] is allocated
ld a, [wFsInode]
call inode_ptr