aboutsummaryrefslogtreecommitdiffstats
path: root/include
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 /include
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 'include')
-rw-r--r--include/gbos.inc14
1 files changed, 12 insertions, 2 deletions
diff --git a/include/gbos.inc b/include/gbos.inc
index 9099bc9..589c33c 100644
--- a/include/gbos.inc
+++ b/include/gbos.inc
@@ -185,6 +185,8 @@ DEF NET_CLOSE EQU 4 ; NR_SOCK
DEF NET_BIND EQU 5 ; NR_SOCK, NR_PORT -> bind local port (UDP)
DEF NET_POLL EQU 6 ; pump RX once (answer pings) -> A=0
DEF NET_SETIP EQU 7 ; set our IPv4 address from NR_IP (DHCP)
+DEF NET_LISTEN EQU 9 ; NR_SOCK, NR_PORT -> passive open (wait for a SYN)
+DEF NET_ACCEPT EQU 10 ; NR_SOCK -> A=0 connected / $FE nothing yet (no block)
DEF NET_RECVNB EQU 8 ; like NET_RECV but never blocks: pump once, then
; A=len if a datagram was buffered, $FE if none yet,
; 0 on TCP EOF. Lets programs own their timeouts (ping).
@@ -217,14 +219,21 @@ DEF BLK_DATA0 EQU 4 ; first data block
DEF FS_VERSION EQU 3 ; bumped: dirs now carry "."/".." entries
DEF NINODES EQU 32
DEF ROOT_INO EQU 1
-DEF NDIRECT EQU 8 ; direct block pointers per inode -> files <= 2 KiB
+DEF NDIRECT EQU 12 ; direct block pointers per inode -> files <= 3 KiB
+ ; (4..15: the whole tail of the 16-byte inode. It
+ ; was 8, and bytes 12-15 were unused - but nothing
+ ; bounds-checked the index, so a file past 2 KiB
+ ; simply kept walking: first through those 4 spare
+ ; bytes, then into the NEXT inode. sys_getb/sys_putb
+ ; now stop at NDIRECT.)
DEF DIRENTS EQU 16 ; directory entries per block (256/16)
; inode fields (16 bytes)
DEF I_TYPE EQU 0 ; 0=free 1=file 2=dir
DEF I_NLINK EQU 1
DEF I_SIZE EQU 2 ; 16-bit
-DEF I_BLOCKS EQU 4 ; 8 direct block pointers (1 byte each; 0=none)
+DEF I_BLOCKS EQU 4 ; NDIRECT direct block pointers (1 byte each, 0=none)
+ ; - fills the inode to its 16-byte end
DEF IT_FREE EQU 0
DEF IT_FILE EQU 1
DEF IT_DIR EQU 2
@@ -296,5 +305,6 @@ DEF PROG_GREP EQU 33
DEF PROG_MORE EQU 34
DEF PROG_CP EQU 35
DEF PROG_NC EQU 36
+DEF PROG_HTTPD EQU 37
ENDC