VulpesOS/tundra/probes/armv7-gecko-launch.c
2026-10-22 20:42:26 +02:00

71 lines
3.5 KiB
C

/* SPDX-License-Identifier: MPL-2.0 */
/* Temporary ARM EABI runtime probe. Private mount namespace; Gecko runs as shell. */
#ifndef ROOT
#define ROOT "/data/local/tmp/vulpes-gecko-armhf/rootfs"
#endif
#ifndef GECKO
#define GECKO "/usr/lib/firefox-esr/firefox-esr"
#endif
static long call(long n, long a, long b, long c, long d, long e) {
register long r0 __asm__("r0") = a;
register long r1 __asm__("r1") = b;
register long r2 __asm__("r2") = c;
register long r3 __asm__("r3") = d;
register long r4 __asm__("r4") = e;
register long r7 __asm__("r7") = n;
__asm__ volatile("svc 0" : "+r"(r0) : "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7) : "memory", "cc");
return r0;
}
static void output(const char *s) {
long len=0; while(s[len])len++;
call(4,2,(long)s,len,0,0);
}
static void check(long result, const char *operation) {
if(result>=0)return;
output(operation);output(" failed, errno=");
char buf[16];long i=15;buf[i]=0;result=-result;
do {buf[--i]='0'+result%10;result/=10;}while(result);
output(buf+i);output("\n");call(1,1,0,0,0,0);for(;;){}
}
static void device(const char *path, long minor) {
check(call(14,(long)path,8192|0666,256|minor,0,0),"mknod");
check(call(15,(long)path,0666,0,0,0),"device permissions");
}
__attribute__((noreturn)) void run(long *stack) {
long argc=stack[0]; char **argv=(char **)(stack+1);
int render=argc==2 && argv[1][0]=='r';
if(argc!=2 || (!render && argv[1][0]!='v')) {
output("Use version or render\n");call(1,2,0,0,0,0);for(;;){}
}
long fd=call(5,(long)"/proc/self/oom_score_adj",1,0,0,0);
check(fd,"oom_score_adj open");check(call(4,fd,(long)"1000",4,0,0),"oom_score_adj write");call(6,fd,0,0,0,0);
check(call(337,0x20000|0x40000000,0,0,0,0),"unshare mount and network namespaces");
check(call(21,0,(long)"/",0,16384|262144,0),"private mount propagation");
check(call(21,(long)"/proc",(long)ROOT "/proc",0,4096,0),"bind proc");
/* /data is nodev: character devices need a private tmpfs mount. */
check(call(21,(long)"tmpfs",(long)ROOT "/dev",(long)"tmpfs",2,(long)"size=1m,mode=0755"),"private devices");
device(ROOT "/dev/null",3);device(ROOT "/dev/zero",5);
device(ROOT "/dev/random",8);device(ROOT "/dev/urandom",9);
check(call(39,(long)ROOT "/dev/shm",01777,0,0,0),"shared memory directory");
check(call(21,(long)"tmpfs",(long)ROOT "/dev/shm",(long)"tmpfs",2|4,(long)"size=64m,mode=1777"),"private shared memory");
check(call(61,(long)ROOT,0,0,0,0),"chroot");
check(call(12,(long)"/",0,0,0,0),"chdir");
check(call(206,0,0,0,0,0),"drop supplementary groups");
check(call(214,2000,0,0,0,0),"setgid");
check(call(213,2000,0,0,0,0),"setuid");
check(call(172,38,1,0,0,0),"no new privileges");
char *env[]={"HOME=/work", "TMPDIR=/tmp", "MOZ_HEADLESS=1",
"MOZ_HEADLESS_WIDTH=240", "MOZ_HEADLESS_HEIGHT=320", "LANG=C",
"FONTCONFIG_PATH=/etc/fonts", "MOZ_CRASHREPORTER_DISABLE=1",
"LD_LIBRARY_PATH=/opt/firefox:/usr/lib/firefox-esr:/lib/arm-linux-gnueabihf:/usr/lib/arm-linux-gnueabihf",0};
char *versionArgs[]={GECKO,"--version",0};
char *renderArgs[]={GECKO,"--headless","--no-remote",
"--profile","/work/profile","--window-size","240,320",
"--screenshot","/work/gecko.png","file:///work/test.html",0};
output("VULPES ARMv7 Gecko probe: isolated mounts/network, uid=2000\n");
check(call(11,(long)versionArgs[0],(long)(render?renderArgs:versionArgs),(long)env,0,0),"exec Gecko");
call(1,1,0,0,0,0);for(;;){}
}
__attribute__((naked,noreturn)) void _start(void) {
__asm__ volatile("mov r0, sp\nb run");
}