code wiki / _hdl_build / nx_acl.nx
nx_acl.nx source
↩ module page · 68 lines · 5177 B
1// nx_acl.nx -- GROUPS + ACLs (deepens AUTH-USERS beyond nx_users' owner/other model). POSIX-style: users have a
2// primary gid + supplementary group membership; resources carry owner-uid + owner-gid + 9 permission bits
3// (user rwx / group rwx / other rwx); an access check picks the right class. Sovereign, deterministic.
4// T1 owner gets the USER bits. T2 a group member gets the GROUP bits (r-x: read yes / write no).
5// T3 a non-member gets the OTHER bits. T4 teeth: a non-member is denied; group-write denied when group lacks w.
6// expect_exit: 0 Sovereign: nx_syscalls. NEVER-BRICK: userspace permission logic, 0 firmware.
7import "nx_syscalls.nx"
8import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
9import "nx_g_puts_lib.nx"
10
11// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
12// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
13// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
14// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
15func g_pn(v: i64) -> i64 { nxi_out(v); return 0 }
16func ck(name: *u8, c: i64) -> i64 { if c==1 { g_puts(" PASS " as *u8) } else { g_puts(" FAIL " as *u8) } g_puts(name); g_puts("\n" as *u8); return c }
17
18const MAXG: i64 = 8 // max groups per user
19// is gid in user `u`'s group list? gmemb[u*MAXG..] terminated by -1.
20func in_group(gmemb: *i64, u: i64, gid: i64) -> i64 { var k: i64=0; while k<MAXG { let g: i64=gmemb[u*MAXG+k]; if g==(0-1) { return 0 } if g==gid { return 1 } k=k+1 } return 0 }
21// perm bits: user r=1<<8 w=1<<7 x=1<<6 | group r=1<<5 w=1<<4 x=1<<3 | other r=1<<2 w=1<<1 x=1<<0
22// pick the permission class for (uid,gid-list) on a resource(owner,ogid,perms); want: 2=read,1=write,0=exec(bit index within class)
23func acl_allow(gmemb: *i64, uid: i64, owner: i64, ogid: i64, perms: i64, wantbit: i64) -> i64 {
24 var shift: i64=0 // class base shift: other=0
25 if uid==owner { shift=6 } // user class
26 else { if in_group(gmemb, uid, ogid)==1 { shift=3 } } // group class
27 return (perms>>(shift+wantbit))&1
28}
29
30func main() -> i64 {
31 g_puts("nx_acl (GROUPS + ACLs: POSIX-style user/group/other permission classes)\n" as *u8)
32 var pass: i64=0; var total: i64=0
33 // users: alice uid1 groups{10}, bob uid2 groups{10,20}, carol uid3 groups{30}
34 let NU: i64=3
35 let gmemb: *i64 = sys_mmap(NU*MAXG*8) as *i64
36 var i: i64=0; while i<NU*MAXG { gmemb[i]=0-1; i=i+1 }
37 gmemb[1*MAXG+0]=10 // alice in g10
38 gmemb[2*MAXG+0]=10; gmemb[2*MAXG+1]=20 // bob in g10,g20
39 gmemb[3*MAXG+0]=30 // carol in g30
40
41 // resource owned by alice(uid1), group g10, perms rwx r-x --- = user(111) group(101) other(000)
42 // = (1<<8)|(1<<7)|(1<<6) | (1<<5)|(1<<3) = 0x1C0 | 0x28 = 0x1E8
43 let owner: i64=1; let ogid: i64=10; let perms: i64=0x1E8
44 // wantbit: read=2, write=1, exec=0
45
46 var t1: i64=0; if acl_allow(gmemb,1,owner,ogid,perms,2)==1 { if acl_allow(gmemb,1,owner,ogid,perms,1)==1 { if acl_allow(gmemb,1,owner,ogid,perms,0)==1 { t1=1 } } }
47 pass=pass+ck("T1: owner (alice) gets USER bits -- rwx all allowed" as *u8, t1); total=total+1
48
49 var t2: i64=0; if acl_allow(gmemb,2,owner,ogid,perms,2)==1 { if acl_allow(gmemb,2,owner,ogid,perms,1)==0 { if acl_allow(gmemb,2,owner,ogid,perms,0)==1 { t2=1 } } }
50 g_puts(" T2 bob (group g10): read="); g_pn(acl_allow(gmemb,2,owner,ogid,perms,2)); g_puts(" write="); g_pn(acl_allow(gmemb,2,owner,ogid,perms,1)); g_puts(" exec="); g_pn(acl_allow(gmemb,2,owner,ogid,perms,0)); g_puts("\n" as *u8)
51 pass=pass+ck("T2: a group member (bob in g10) gets GROUP bits (r-x: read yes, write NO, exec yes)" as *u8, t2); total=total+1
52
53 var t3: i64=0; if acl_allow(gmemb,3,owner,ogid,perms,2)==0 { if acl_allow(gmemb,3,owner,ogid,perms,1)==0 { t3=1 } }
54 g_puts(" T3 carol (not owner, not in g10): read="); g_pn(acl_allow(gmemb,3,owner,ogid,perms,2)); g_puts(" write="); g_pn(acl_allow(gmemb,3,owner,ogid,perms,1)); g_puts(" (other=000)\n" as *u8)
55 pass=pass+ck("T3: a non-member (carol) gets OTHER bits -- here --- (all denied)" as *u8, t3); total=total+1
56
57 var t4: i64=0; if acl_allow(gmemb,3,owner,ogid,perms,2)==0 { if acl_allow(gmemb,2,owner,ogid,perms,1)==0 { t4=1 } }
58 pass=pass+ck("T4 (teeth): non-member denied; group-write denied when the group class lacks w" as *u8, t4); total=total+1
59
60 var okall: i64=0; if pass==total { okall=1 }
61 g_puts("---- nx_acl: passed "); g_pn(pass); g_puts(" / "); g_pn(total); g_puts(" ----\n" as *u8)
62 if okall==1 {
63 let logf: i64=sys_openat_append("knowledge/status/acl.log" as *u8, 420)
64 if logf>=0 { let z: i64=sys_write(logf,"NXACL GREEN: POSIX-style user/group/other ACLs -- owner=user bits, member=group bits, else other; teeth enforced\n" as *u8,109); sys_close(logf) }
65 g_puts("verdict=GREEN (groups + ACLs: POSIX-style user/group/other permission classes; deepens AUTH-USERS)\n" as *u8); sys_exit(0); return 0
66 }
67 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1
68}