├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── hl.c ├── java-17.c ├── mono.c ├── rigg.1 ├── rigg.c ├── rigg.h ├── rigg_mono.h ├── rigg_unveil.c ├── rigg_unveil.h └── test ├── Makefile ├── MonoInvisible.cs └── MonoVisible.cs /.gitignore: -------------------------------------------------------------------------------- 1 | /rigg 2 | *.a 3 | *.o 4 | *.so 5 | *.so.* 6 | *.out 7 | *.core 8 | *.plist 9 | *.d 10 | *.exe 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023-2024 Thomas Frohwein 2 | 3 | Permission to use, copy, modify, and distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROG = rigg 2 | SRCS = rigg.c rigg_unveil.c mono.c hl.c 3 | 4 | BINDIR ?= /usr/local/bin 5 | MANDIR ?= /usr/local/man/man 6 | WARNINGS ?= Yes 7 | 8 | HL_CFLAGS ?= -I/usr/local/include -I/usr/local/include/hl 9 | J17_CFLAGS ?= -I/usr/local/jdk-17/include 10 | MONO_CFLAGS ?= -I/usr/local/include/mono-2.0 11 | COPTS += ${HL_CFLAGS} ${MONO_CFLAGS} 12 | 13 | LDFLAGS += -L/usr/local/lib -Wl,-z,wxneeded -Wl,-z,nobtcfi 14 | LDADD += -lmonosgen-2.0 -lhl -lhl_module 15 | 16 | CLEANFILES += test/*.exe 17 | 18 | readme: 19 | mandoc -T markdown rigg.1 > README.md 20 | 21 | .PHONY: test 22 | test: 23 | ${MAKE} -C test clean regress 24 | 25 | uninstall: 26 | rm -f ${DESTDIR}${BINDIR}/${PROG} 27 | rm -f ${_MAN_INST} 28 | 29 | .include 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RIGG(1) - General Commands Manual 2 | 3 | # NAME 4 | 5 | **rigg** - run independent games 6 | 7 | # SYNOPSIS 8 | 9 | **rigg** 10 | \[**-v**] 11 | \[**-u** *strict* | *permissive* | *none*] 12 | *engine* 13 | *file* 14 | \[*game arguments*] 15 | **rigg** 16 | \[**-hl**] 17 | 18 | # DESCRIPTION 19 | 20 | **rigg** 21 | serves as a thin, 22 | OpenBSD-adapted runtime wrapper for independent games based on certain engines 23 | (see 24 | *engine*) 25 | . 26 | **rigg** 27 | handles visibility of files by using 28 | unveil(2) 29 | to hide those that conflict with execution on 30 | OpenBSD. 31 | This solves a common problem with commercial games based on open-source 32 | frameworks like FNA, LibGDX, or HashLink. 33 | In addition, 34 | **rigg** 35 | also enforces a minimum-necessary filesystem view by default via 36 | unveil(2). 37 | Some basic engine configuration for 38 | OpenBSD 39 | like dllmap for 40 | mono(1) 41 | is included. 42 | More complex configuration like filesystem changes or 43 | game-specific environment variables are out of scope. 44 | 45 | The arguments are as follows: 46 | 47 | *engine* 48 | 49 | > Specify the engine to use. 50 | > Can select from: 51 | > *mono*, 52 | > *hl*. 53 | 54 | *file* 55 | 56 | > The file to launch with the engine, e.g. 57 | > *Game.exe* 58 | > (mono) 59 | > or 60 | > *hlboot.dat* 61 | > (hl). 62 | 63 | **-h** 64 | 65 | > Show usage information. 66 | 67 | **-l** 68 | 69 | > List the binaries of supported engines. 70 | 71 | **-u** 72 | 73 | > Set unveil mode. 74 | > *strict* 75 | > is the default and reduces read/write/create/execute permissions to a limited 76 | > set of paths and hides game files that interfere with execution on 77 | > OpenBSD. 78 | > *permissive* 79 | > only hides game files when needed for engine execution, but otherwise doesn't 80 | > restrict filesystem access. 81 | > *none* 82 | > disables all uses of unveil and is generally equivalent to running the 83 | > *engine*'s 84 | > own binary. 85 | 86 | **-v** 87 | 88 | > Enable verbose output. 89 | 90 | # EXIT STATUS 91 | 92 | The **rigg** utility exits 0 on success, and >0 if an error occurs. 93 | After successful launch of the engine, the 94 | *engine*'s 95 | exit status is returned. 96 | See engine-specific documentation. 97 | 98 | # EXAMPLES 99 | 100 | Run Mono game 101 | *Game.exe* 102 | with a game-specific flag 103 | **-windowed**: 104 | 105 | $ rigg mono Game.exe -windowed 106 | 107 | Run HashLink game 108 | *hlboot.dat* 109 | with verbose output: 110 | 111 | $ rigg -v hl hlboot.dat 112 | 113 | # SEE ALSO 114 | 115 | mono(1), 116 | unveil(2) 117 | 118 | # AUTHORS 119 | 120 | Thomas Frohwein <[thfr@openbsd.org](mailto:thfr@openbsd.org)> 121 | 122 | # CAVEATS 123 | 124 | The selection of directories that are 125 | unveil(2)ed 126 | may not cover all potential use cases. 127 | Some games fail to launch or have bugs in 128 | *strict* 129 | mode if they try to 130 | stat(2) 131 | */home* 132 | or other hidden directories. 133 | 134 | OpenBSD 7.5 - April 28, 2024 135 | -------------------------------------------------------------------------------- /hl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C)2015-2016 Haxe Foundation 3 | * Copyright (C)2023-2024 Thomas Frohwein 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a 6 | * copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | * DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include "rigg.h" 37 | #include "rigg_unveil.h" 38 | 39 | #define pprintf printf 40 | #define pfopen fopen 41 | #define pcompare strcmp 42 | #define ptoi atoi 43 | #define PSTR(x) x 44 | 45 | typedef char pchar; 46 | 47 | static const unveil_pair unveils[] = { 48 | { "/usr/lib", "r" }, 49 | { "/usr/local/lib", "r" }, 50 | { "/usr/X11R6", "r" }, 51 | { "/usr/share", "r" }, 52 | { "/dev", "rw" }, 53 | { "/tmp", "rwc" }, 54 | { ".", "rwc" } 55 | }; 56 | 57 | const char *unveil_globs[] = { 58 | "*.hdll", 59 | "*.so", 60 | "*.so.*" 61 | }; 62 | 63 | static const unveil_quirk unveil_quirks[] = { 64 | /* { file, env_var, unveilpath, permissions }, */ 65 | { "../res.pak", "", "..", "rwc" } /* Nuclear Blaze */ 66 | }; 67 | 68 | typedef struct { 69 | pchar *file; 70 | hl_code *code; 71 | hl_module *m; 72 | vdynamic *ret; 73 | int file_time; 74 | } main_context; 75 | 76 | static int pfiletime( pchar *file ) { 77 | struct stat st; 78 | stat(file,&st); 79 | return (int)st.st_mtime; 80 | } 81 | 82 | static hl_code *load_code( const pchar *file, char **error_msg, bool print_errors ) { 83 | hl_code *code; 84 | FILE *f = pfopen(file,"rb"); 85 | int pos, size; 86 | char *fdata; 87 | if( f == NULL ) { 88 | if( print_errors ) pprintf("File not found '%s'\n",file); 89 | return NULL; 90 | } 91 | fseek(f, 0, SEEK_END); 92 | size = (int)ftell(f); 93 | fseek(f, 0, SEEK_SET); 94 | fdata = malloc(size); 95 | pos = 0; 96 | while( pos < size ) { 97 | int r = (int)fread(fdata + pos, 1, size-pos, f); 98 | if( r <= 0 ) { 99 | if( print_errors ) pprintf("Failed to read '%s'\n",file); 100 | return NULL; 101 | } 102 | pos += r; 103 | } 104 | fclose(f); 105 | code = hl_code_read((unsigned char*)fdata, size, error_msg); 106 | free(fdata); 107 | return code; 108 | } 109 | 110 | static bool check_reload( main_context *m ) { 111 | int time = pfiletime(m->file); 112 | bool changed; 113 | if( time == m->file_time ) 114 | return false; 115 | char *error_msg = NULL; 116 | hl_code *code = load_code(m->file, &error_msg, false); 117 | if( code == NULL ) 118 | return false; 119 | changed = hl_module_patch(m->m, code); 120 | m->file_time = time; 121 | hl_code_free(code); 122 | return changed; 123 | } 124 | 125 | static void handle_signal( int signum ) { 126 | signal(signum, SIG_DFL); 127 | printf("SIGNAL %d\n",signum); 128 | hl_dump_stack(); 129 | fflush(stdout); 130 | raise(signum); 131 | } 132 | 133 | static void setup_handler(void) { 134 | struct sigaction act; 135 | act.sa_sigaction = NULL; 136 | act.sa_handler = handle_signal; 137 | act.sa_flags = 0; 138 | sigemptyset(&act.sa_mask); 139 | signal(SIGPIPE, SIG_IGN); 140 | sigaction(SIGSEGV,&act,NULL); 141 | sigaction(SIGTERM,&act,NULL); 142 | } 143 | 144 | int hl(int argc, pchar *argv[]) { 145 | static vclosure cl; 146 | char *error_msg = NULL; 147 | int debug_port = -1; 148 | bool debug_wait = false; 149 | bool hot_reload = false; 150 | int profile_count = -1; 151 | main_context ctx; 152 | bool isExc = false; 153 | pchar *file = *argv++; 154 | argc--; 155 | 156 | vprintf("launching global init\n"); 157 | hl_global_init(); 158 | hl_sys_init((void**)argv,argc,file); 159 | vprintf("registering main thread\n"); 160 | hl_register_thread(&ctx); 161 | ctx.file = file; 162 | vprintf("loading code from %s\n", file); 163 | ctx.code = load_code(file, &error_msg, true); 164 | if( ctx.code == NULL ) { 165 | if( error_msg ) printf("%s\n", error_msg); 166 | return 1; 167 | } 168 | 169 | vprintf("initializing module\n"); 170 | ctx.m = hl_module_alloc(ctx.code); 171 | if( ctx.m == NULL ) 172 | return 2; 173 | if( !hl_module_init(ctx.m,hot_reload) ) 174 | return 3; 175 | if( hot_reload ) { 176 | ctx.file_time = pfiletime(ctx.file); 177 | hl_setup_reload_check(check_reload,&ctx); 178 | } 179 | hl_code_free(ctx.code); 180 | if( debug_port > 0 && !hl_module_debug(ctx.m,debug_port,debug_wait) ) { 181 | fprintf(stderr,"Could not start debugger on port %d",debug_port); 182 | return 4; 183 | } 184 | cl.t = ctx.code->functions[ctx.m->functions_indexes[ctx.m->code->entrypoint]].type; 185 | cl.fun = ctx.m->functions_ptrs[ctx.m->code->entrypoint]; 186 | cl.hasValue = 0; 187 | vprintf("setting up signal handler\n\n"); 188 | setup_handler(); 189 | hl_profile_setup(profile_count); 190 | 191 | /* unveil */ 192 | glob_t g; 193 | unveil_quirk uvq; 194 | unveil_pair uvp; 195 | char mesa_shader_cache[PATH_MAX]; 196 | char sndio_dir[PATH_MAX]; 197 | char xauthority[PATH_MAX]; 198 | char uvq_fullpath[PATH_MAX]; 199 | char *home_dir; 200 | char *match; 201 | char *uvq_ev; 202 | 203 | if (umode >= STRICT) { 204 | /* quirks first */ 205 | for (size_t i = 0; i < sizeof(unveil_quirks) / sizeof(unveil_quirks[0]); i++) { 206 | uvq = unveil_quirks[i]; 207 | if (access(uvq.file, F_OK) == -1) 208 | continue; 209 | if ((uvq_ev = getenv(uvq.env_var)) == NULL) { 210 | unveil_err(uvq.path, uvq.permissions); 211 | } 212 | else { 213 | if (snprintf(uvq_fullpath, sizeof(uvq_fullpath), 214 | "%s/%s", getenv(uvq.env_var), uvq.path) < 0) { 215 | err(1, "snprintf"); 216 | } 217 | unveil_err(uvq_fullpath, uvq.permissions); 218 | } 219 | } 220 | 221 | for (size_t i = 0; i < sizeof(unveils) / sizeof(unveils[0]); i++) { 222 | uvp = unveils[i]; 223 | unveil_err(uvp.path, uvp.permissions); 224 | } 225 | if ((home_dir = getenv("HOME")) == NULL) 226 | err(1, "getenv(\"HOME\")"); 227 | if (snprintf(mesa_shader_cache, sizeof(mesa_shader_cache), 228 | "%s/.cache/mesa_shader_cache", home_dir) < 0) { 229 | err(1, "snprintf"); 230 | } 231 | else { 232 | unveil_err(mesa_shader_cache, "rwc"); 233 | } 234 | if (snprintf(sndio_dir, sizeof(sndio_dir), "%s/.sndio", home_dir) < 0) 235 | err(1, "snprintf"); 236 | else { 237 | unveil_err(sndio_dir, "rwc"); 238 | } 239 | if (snprintf(xauthority, sizeof(xauthority), "%s/.Xauthority", home_dir) < 0) { 240 | err(1, "snprintf"); 241 | } 242 | else { 243 | unveil_err(xauthority, "rw"); 244 | } 245 | } else if (umode >= PERMISSIVE) { 246 | unveil_err("/", "rwcx"); 247 | } 248 | 249 | if (umode >= PERMISSIVE) { 250 | g.gl_offs = 0; 251 | for (size_t i = 0; i < sizeof(unveil_globs) / sizeof(unveil_globs[0]); i++) { 252 | if (glob(unveil_globs[i], i > 0 ? GLOB_APPEND | GLOB_NOCHECK : 253 | GLOB_NOCHECK, NULL, &g) != 0) 254 | err(1, "glob"); 255 | } 256 | while ((match = *g.gl_pathv++) != NULL) { 257 | unveil_err(match, ""); 258 | } 259 | 260 | unveil_err(NULL, NULL); 261 | vprintf("\n"); 262 | } 263 | 264 | vprintf("entering main program\n\n"); 265 | ctx.ret = hl_dyn_call_safe(&cl,NULL,0,&isExc); 266 | 267 | vprintf("cleaning up...\n"); 268 | hl_profile_end(); 269 | if( isExc ) { 270 | varray *a = hl_exception_stack(); 271 | uprintf(USTR("Uncaught exception: %s\n"), hl_to_string(ctx.ret)); 272 | for(int i=0;isize;i++) 273 | uprintf(USTR("Called from %s\n"), hl_aptr(a,uchar*)[i]); 274 | hl_debug_break(); 275 | hl_global_free(); 276 | return 1; 277 | } 278 | 279 | vprintf("cleaning up some more...\n"); 280 | hl_module_free(ctx.m); 281 | hl_free(&ctx.code->alloc); 282 | 283 | // do not call hl_unregister_thread() or hl_global_free will display error 284 | // on global_lock if there are threads that are still running (such as debugger) 285 | hl_global_free(); 286 | 287 | return 0; 288 | } 289 | -------------------------------------------------------------------------------- /java-17.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2024 Thomas Frohwein 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include /* /usr/local/jdk-1.8.0/include/jni.h etc for 11, 17 */ 23 | 24 | #include "rigg.h" 25 | #include "rigg_unveil.h" 26 | 27 | static const unveil_pair unveils[] = { 28 | }; 29 | 30 | 31 | int java17(int argc, char** argv) { 32 | 33 | errx(1, "not implemented: java"); 34 | return 1; 35 | 36 | #if 0 37 | /* https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html */ 38 | 39 | JavaVM *jvm; 40 | JNIEnv *env; 41 | JavaVMInitArgs vm_args; 42 | JavaVMOption *options = new JavaVMOption[1]; 43 | 44 | options[0].optionString = "-Djava.class.path=/usr/local/jdk-17"; 45 | vm_args.version = JNI_VERSION_1_6; 46 | vm_args.nOptions = 1; 47 | vm_args.options = options; 48 | vm_args.ignoreUnrecognized = false 49 | 50 | JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); 51 | delete options; 52 | 53 | /* invoke the specified method */ 54 | jclass cls = env->FindClass("Main"); /* XXX: replace Main */ 55 | jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V"); /* XXX: replace test */ 56 | env->CallStaticVoidMethod(cls, mid, 100); 57 | 58 | jvm->DestroyJavaVM(); 59 | #endif 60 | 61 | #if 0 62 | vprintf("unveiling:\n"); 63 | for (i = 0; i < sizeof(unveils) / sizeof(unveils[0]); i++) { 64 | uvp = unveils[i]; 65 | vprintf(UNVEIL_VPRINT_FMT, uvp.path, uvp.permissions); 66 | unveil_err(uvp.path, uvp.permissions); 67 | } 68 | 69 | if ((home_dir = getenv("HOME")) == NULL) 70 | err(1, "getenv(\"HOME\")"); 71 | 72 | if (snprintf(config_dir, sizeof(config_dir), "%s/.config", home_dir) < 0) 73 | err(1, "snprintf"); 74 | else { 75 | vprintf(UNVEIL_VPRINT_FMT, config_dir, "rwc"); 76 | unveil_err(config_dir, "rwc"); 77 | } 78 | if (snprintf(localshare_dir, sizeof(localshare_dir), "%s/.local/share", home_dir) < 0) 79 | err(1, "snprintf"); 80 | else { 81 | vprintf(UNVEIL_VPRINT_FMT, localshare_dir, "rwc"); 82 | unveil_err(localshare_dir, "rwc"); 83 | } 84 | if (snprintf(sndio_dir, sizeof(sndio_dir), "%s/.sndio", home_dir) < 0) 85 | err(1, "snprintf"); 86 | else { 87 | vprintf(UNVEIL_VPRINT_FMT, sndio_dir, "rwc"); 88 | unveil_err(sndio_dir, "rwc"); 89 | } 90 | if (snprintf(xauthority, sizeof(xauthority), "%s/.Xauthority", home_dir) < 0) 91 | err(1, "snprintf"); 92 | else { 93 | vprintf(UNVEIL_VPRINT_FMT, xauthority, "rw"); 94 | unveil_err(xauthority, "rw"); 95 | } 96 | if ((xdg_data_home = getenv("XDG_DATA_HOME")) != NULL) { 97 | vprintf(UNVEIL_VPRINT_FMT, xdg_data_home, "rwc"); 98 | unveil_err(xdg_data_home, "rwc"); 99 | } 100 | 101 | /* hide incompatible bundled files */ 102 | for (i = 0; i < sizeof(unveil_hide) / sizeof(unveil_hide[0]); i++) { 103 | if (access(unveil_hide[i], F_OK) == 0) { 104 | vprintf(UNVEIL_VPRINT_FMT, unveil_hide[i], ""); 105 | unveil_err(unveil_hide[i], ""); 106 | } 107 | } 108 | 109 | vprintf("\n"); 110 | 111 | unveil_err(NULL, NULL); 112 | 113 | vprintf("executing mono jit with the following arguments:"); 114 | for (i = 0; i < argc; i++) 115 | vprintf(" \"%s\"", argv[i]); 116 | vprintf("\n\n"); 117 | 118 | vprintf("cleaning up...\n"); 119 | 120 | return r; 121 | #endif 122 | 123 | } 124 | -------------------------------------------------------------------------------- /mono.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2024 Thomas Frohwein 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "rigg.h" 29 | #include "rigg_mono.h" 30 | #include "rigg_unveil.h" 31 | 32 | /* XXX: Vulkan will need: /home (SDL_GetPrefPath), /dev rwcx */ 33 | static const unveil_pair unveils[] = { 34 | { MONO_PATH_DEFAULT, "r" }, 35 | { "/usr/lib", "r" }, 36 | { "/usr/local/lib", "r" }, 37 | { "/usr/X11R6", "r" }, 38 | { "/usr/share", "r" }, 39 | { "/etc", "r" }, /* XXX: only /etc/mono ? */ 40 | { "/dev", "rw" }, /* XXX: Vulkan: cx; also compare unveilro */ 41 | { "/tmp", "rwc" }, 42 | { ".", "rwc" } 43 | }; 44 | 45 | static const unveil_quirk unveil_quirks[] = { 46 | { "DadQuest.exe", "HOME", "Library/Application Support/DadQuest", "rwc" }, 47 | { "NeuroVoider.exe", "HOME", ".neurovoider", "rwc" }, 48 | { "NeuroVoider.exe", "", "NeuroVoider.exe.config", "" } 49 | }; 50 | 51 | const char *unveil_hide[] = { 52 | "FNA.dll", 53 | "FNA.dll.config", 54 | "I18N.CJK.dll", 55 | "I18N.MidEast.dll", 56 | "I18N.Other.dll", 57 | "I18N.Rare.dll", 58 | "I18N.West.dll", 59 | "I18N.dll", 60 | "Microsoft.CSharp.dll", 61 | "Microsoft.Xna.Framework.Game.dll", 62 | "Microsoft.Xna.Framework.GamerServices.dll", 63 | "Microsoft.Xna.Framework.Graphics.dll", 64 | "Microsoft.Xna.Framework.Input.Touch.dll", 65 | "Microsoft.Xna.Framework.Net.dll", 66 | "Microsoft.Xna.Framework.Storage.dll", 67 | "Microsoft.Xna.Framework.Video.dll", 68 | "Microsoft.Xna.Framework.Xact.dll", 69 | "Microsoft.Xna.Framework.dll", 70 | "Mono.CSharp.dll", 71 | "Mono.Posix.dll", 72 | "Mono.Security.dll", 73 | "MonoGame.Framework.dll.config", 74 | "System.ComponentModel.DataAnnotations.dll", 75 | "System.Configuration.dll", 76 | "System.Configuration.Install.dll", 77 | "System.Core.dll", 78 | "System.Data.dll", 79 | "System.Design.dll", 80 | "System.Drawing.dll", 81 | "System.IO.Compression.FileSystem.dll", 82 | "System.IO.Compression.dll", 83 | "System.Management.dll", 84 | "System.Net.dll", 85 | "System.Numerics.dll", 86 | "System.Runtime.Serialization.dll", 87 | "System.Security.dll", 88 | "System.ServiceModel.dll", 89 | "System.Transactions.dll", 90 | "System.Web.Extensions.dll", 91 | "System.Web.Http.dll", 92 | "System.Web.Services.dll", 93 | "System.Web.dll", 94 | "System.Windows.Forms.dll", 95 | "System.Xml.Linq.dll", 96 | "System.Xml.dll", 97 | "System.dll", 98 | "WindowsBase.dll", 99 | "libMonoPosixHelper.so", 100 | "libMonoPosixHelper.so.x86", 101 | "libMonoPosixHelper.so.x86_64", 102 | "libSteamworksNative.so", 103 | "mscorlib.dll", 104 | "x86", 105 | "x64" 106 | }; 107 | 108 | int mono(int argc, char** argv) { 109 | MonoDomain *domain; 110 | MonoAssembly *assembly; 111 | unveil_pair uvp; 112 | char *file = argv[0]; 113 | char *home_dir; 114 | char *xdg_data_home; 115 | char *xdg_config_home; 116 | char config_dir[PATH_MAX]; 117 | char localshare_dir[PATH_MAX]; 118 | char mesa_shader_cache[PATH_MAX]; 119 | char mono_userdir[PATH_MAX]; /* ~/.mono/ */ 120 | char sndio_dir[PATH_MAX]; 121 | char xauthority[PATH_MAX]; 122 | char xcompose[PATH_MAX]; 123 | char xdefaults[PATH_MAX]; 124 | int r; 125 | 126 | vprintf("parsing Dllmap\n"); 127 | mono_config_parse_memory(Dllmap); /* void */ 128 | if (setenv("MONO_PATH", MONO_PATH_DEFAULT, 0) == -1) 129 | err(1, "setenv"); /* setenv BEFORE mono_jit_init */ 130 | vprintf("initializing mono jit for %s\n", file); 131 | if ((domain = mono_jit_init(file)) == NULL) 132 | err(1, "mono_jit_init"); 133 | vprintf("opening executable: %s\n", file); 134 | if ((assembly = mono_domain_assembly_open(domain, file)) == NULL) 135 | err(1, "mono_domain_assembly_open"); 136 | 137 | /* unveils */ 138 | vprintf("\n"); 139 | 140 | /* strict unveil mode */ 141 | if (umode >= STRICT) { 142 | /* quirks first */ 143 | unveil_quirk uvq; 144 | char uvq_fullpath[PATH_MAX]; 145 | for (size_t i = 0; i < sizeof(unveil_quirks) / sizeof(unveil_quirks[0]); i++) { 146 | uvq = unveil_quirks[i]; 147 | if (strncmp(uvq.file, file, MAX_INPUT) != 0) 148 | continue; 149 | if (getenv(uvq.env_var) == NULL) { 150 | unveil_err(uvq.path, uvq.permissions); 151 | } 152 | else { 153 | if (snprintf(uvq_fullpath, sizeof(uvq_fullpath), 154 | "%s/%s", getenv(uvq.env_var), uvq.path) < 0) { 155 | err(1, "snprintf"); 156 | } 157 | unveil_err(uvq_fullpath, uvq.permissions); 158 | } 159 | } 160 | 161 | for (size_t i = 0; i < sizeof(unveils) / sizeof(unveils[0]); i++) { 162 | uvp = unveils[i]; 163 | unveil_err(uvp.path, uvp.permissions); 164 | } 165 | 166 | if ((home_dir = getenv("HOME")) == NULL) 167 | err(1, "getenv(\"HOME\")"); 168 | 169 | if (snprintf(config_dir, sizeof(config_dir), "%s/.config", home_dir) < 0) 170 | err(1, "snprintf"); 171 | else { 172 | unveil_err(config_dir, "rwc"); 173 | } 174 | if (snprintf(localshare_dir, sizeof(localshare_dir), "%s/.local/share", home_dir) < 0) 175 | err(1, "snprintf"); 176 | else { 177 | unveil_err(localshare_dir, "rwc"); 178 | } 179 | if (snprintf(mesa_shader_cache, sizeof(mesa_shader_cache), 180 | "%s/.cache/mesa_shader_cache", home_dir) < 0) 181 | err(1, "snprintf"); 182 | else { 183 | unveil_err(mesa_shader_cache, "rwc"); 184 | } 185 | if (snprintf(mono_userdir, sizeof(mono_userdir), 186 | "%s/.mono", home_dir) < 0) 187 | err(1, "snprintf"); 188 | else { 189 | unveil_err(mono_userdir, "rwc"); 190 | } 191 | if (snprintf(sndio_dir, sizeof(sndio_dir), "%s/.sndio", home_dir) < 0) 192 | err(1, "snprintf"); 193 | else { 194 | unveil_err(sndio_dir, "rwc"); 195 | } 196 | if (snprintf(xauthority, sizeof(xauthority), "%s/.Xauthority", home_dir) < 0) 197 | err(1, "snprintf"); 198 | else { 199 | unveil_err(xauthority, "rw"); 200 | } 201 | if (snprintf(xcompose, sizeof(xcompose), "%s/.XCompose", home_dir) < 0) 202 | err(1, "snprintf"); 203 | else { 204 | unveil_err(xcompose, "rwc"); 205 | } 206 | if (snprintf(xdefaults, sizeof(xcompose), "%s/.Xdefaults", home_dir) < 0) 207 | err(1, "snprintf"); 208 | else { 209 | unveil_err(xdefaults, "rwc"); 210 | } 211 | if ((xdg_data_home = getenv("XDG_DATA_HOME")) != NULL) { 212 | unveil_err(xdg_data_home, "rwc"); 213 | } 214 | if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) != NULL) { 215 | unveil_err(xdg_config_home, "rwc"); 216 | } 217 | } else if (umode >= PERMISSIVE) { 218 | unveil_err("/", "rwcx"); 219 | } 220 | 221 | if (umode >= PERMISSIVE) { 222 | /* hide incompatible bundled files */ 223 | for (size_t i = 0; i < sizeof(unveil_hide) / sizeof(unveil_hide[0]); i++) { 224 | if (access(unveil_hide[i], F_OK) == 0) { 225 | unveil_err(unveil_hide[i], ""); 226 | } 227 | } 228 | 229 | unveil_err(NULL, NULL); 230 | vprintf("\n"); 231 | } 232 | 233 | vprintf("executing mono jit with the following arguments:"); 234 | for (int i = 0; i < argc; i++) 235 | vprintf(" \"%s\"", argv[i]); 236 | vprintf("\n\n"); 237 | /* mono_jit_exec needs argc >= 1 and argv[0] == main_assembly.exe */ 238 | r = mono_jit_exec(domain, assembly, argc, argv); 239 | 240 | vprintf("cleaning up...\n"); 241 | mono_jit_cleanup(domain); /* void */ 242 | 243 | return r; 244 | } 245 | -------------------------------------------------------------------------------- /rigg.1: -------------------------------------------------------------------------------- 1 | .Dd $Mdocdate$ 2 | .Dt RIGG 1 3 | .Os 4 | .Sh NAME 5 | .Nm rigg 6 | .Nd run independent games 7 | .Sh SYNOPSIS 8 | .Nm rigg 9 | .Op Fl v 10 | .Op Fl u Ar strict | permissive | none 11 | .Ar engine 12 | .Ar file 13 | .Op Ar game arguments 14 | .Nm rigg 15 | .Op Fl hl 16 | .Sh DESCRIPTION 17 | .Nm 18 | serves as a thin, 19 | .Ox Ns -adapted runtime wrapper for independent games based on certain engines 20 | .Po 21 | see 22 | .Ar engine 23 | .Pc . 24 | .Nm 25 | handles visibility of files by using 26 | .Xr unveil 2 27 | to hide those that conflict with execution on 28 | .Ox . 29 | This solves a common problem with commercial games based on open-source 30 | frameworks like FNA, LibGDX, or HashLink. 31 | In addition, 32 | .Nm 33 | also enforces a minimum-necessary filesystem view by default via 34 | .Xr unveil 2 . 35 | Some basic engine configuration for 36 | .Ox 37 | like dllmap for 38 | .Xr mono 1 39 | is included. 40 | More complex configuration like filesystem changes or 41 | game-specific environment variables are out of scope. 42 | .Pp 43 | The arguments are as follows: 44 | .Bl -tag -width Ds 45 | .It Ar engine 46 | Specify the engine to use. 47 | Can select from: 48 | .Ar mono , 49 | .Ar hl . 50 | .It Ar file 51 | The file to launch with the engine, e.g. 52 | .Pa Game.exe 53 | .Pq mono 54 | or 55 | .Pa hlboot.dat 56 | .Pq hl . 57 | .It Fl h 58 | Show usage information. 59 | .It Fl l 60 | List the binaries of supported engines. 61 | .It Fl u 62 | Set unveil mode. 63 | .Ar strict 64 | is the default and reduces read/write/create/execute permissions to a limited 65 | set of paths and hides game files that interfere with execution on 66 | .Ox . 67 | .Ar permissive 68 | only hides game files when needed for engine execution, but otherwise doesn't 69 | restrict filesystem access. 70 | .Ar none 71 | disables all uses of unveil and is generally equivalent to running the 72 | .Ar engine Ns 's 73 | own binary. 74 | .It Fl v 75 | Enable verbose output. 76 | .El 77 | .Sh EXIT STATUS 78 | .Ex -std 79 | After successful launch of the engine, the 80 | .Ar engine Ns 's 81 | exit status is returned. 82 | See engine-specific documentation. 83 | .Sh EXAMPLES 84 | Run Mono game 85 | .Pa Game.exe 86 | with a game-specific flag 87 | .Fl windowed : 88 | .Bd -literal -offset indent 89 | $ rigg mono Game.exe -windowed 90 | .Ed 91 | .Pp 92 | Run HashLink game 93 | .Pa hlboot.dat 94 | with verbose output: 95 | .Bd -literal -offset indent 96 | $ rigg -v hl hlboot.dat 97 | .Ed 98 | .Sh SEE ALSO 99 | .Xr mono 1 , 100 | .Xr unveil 2 101 | .Sh AUTHORS 102 | .An -nosplit 103 | .An Thomas Frohwein Aq Mt thfr@openbsd.org 104 | .Sh CAVEATS 105 | The selection of directories that are 106 | .Xr unveil 2 Ns ed 107 | may not cover all potential use cases. 108 | Some games fail to launch or have bugs in 109 | .Ar strict 110 | mode if they try to 111 | .Xr stat 2 112 | .Pa /home 113 | or other hidden directories. 114 | -------------------------------------------------------------------------------- /rigg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2024 Thomas Frohwein 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "rigg.h" 27 | 28 | unveilmode umode = STRICT; 29 | 30 | int verbose = 0; 31 | 32 | __dead static void usage(void) { 33 | fprintf(stderr, 34 | "usage:\trigg [-v] [-u strict|permissive|none] mono|hl file [arguments]\n\trigg [-hl]\n" 35 | ); 36 | exit(1); 37 | } 38 | 39 | int main(int argc, char** argv) { 40 | int ch; 41 | 42 | while ((ch = getopt(argc, argv, "hlu:v")) != -1) { 43 | switch (ch) { 44 | case 'l': 45 | for (size_t i = 0; i < sizeof(runtimes) / sizeof(runtimes[0]); i++) { 46 | printf("%s\n", runtimes[i]); 47 | } 48 | exit(0); 49 | case 'u': 50 | if (strncmp(optarg, "none", 4) == 0) 51 | umode = NONE; 52 | else if (strncmp(optarg, "permissive", 10) == 0) 53 | umode = PERMISSIVE; 54 | else if (strncmp(optarg, "strict", 6) == 0) 55 | umode = STRICT; 56 | else 57 | (void)usage(); 58 | break; 59 | case 'v': 60 | verbose = 1; 61 | break; 62 | case 'h': 63 | default: 64 | usage(); 65 | } 66 | } 67 | argc -= optind; 68 | argv += optind; 69 | 70 | if (argc < 1) 71 | usage(); 72 | 73 | if (strncmp(argv[0], "mono", MAX_INPUT) == 0) { 74 | return mono(argc - 1, argv + 1); 75 | } 76 | else if (strncmp(argv[0], "hl", MAX_INPUT) == 0) { 77 | return hl(argc - 1, argv + 1); 78 | } 79 | 80 | fprintf(stderr, "not a valid engine argument: %s\n", argv[0]); 81 | (void)usage(); 82 | } 83 | -------------------------------------------------------------------------------- /rigg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2024 Thomas Frohwein 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef _RIGG_H 18 | #define _RIGG_H 19 | 20 | #define vprintf(...) do { if (verbose) printf(__VA_ARGS__); } while(0) 21 | 22 | typedef enum { 23 | NONE, 24 | PERMISSIVE, 25 | STRICT 26 | } unveilmode; 27 | 28 | static char *runtimes[2] = { 29 | "hl", 30 | "mono" 31 | }; 32 | 33 | extern unveilmode umode; 34 | extern int verbose; 35 | 36 | __BEGIN_DECLS 37 | int hl(int argc, char** argv); 38 | int mono(int argc, char** argv); 39 | __END_DECLS 40 | 41 | #endif /* _RIGG_H */ 42 | -------------------------------------------------------------------------------- /rigg_mono.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2024 Thomas Frohwein 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef _RIGG_MONO_H 18 | #define _RIGG_MONO_H 19 | 20 | #define MONO_PATH_DEFAULT "/usr/local/share/FNA" 21 | 22 | /* 23 | * Dllmap is a kitchen-sink for any possible issues with looking for the wrong 24 | * library location 25 | */ 26 | const char *Dllmap = "\ 27 | \ 28 | \ 29 | \ 30 | \ 31 | \ 32 | \ 33 | \ 34 | \ 35 | \ 36 | \ 37 | \ 38 | \ 39 | \ 40 | \ 41 | \ 42 | \ 43 | \ 44 | \ 45 | \ 46 | \ 47 | \ 48 | \ 49 | \ 50 | \ 51 | \ 52 | \ 53 | \ 54 | \ 55 | \ 56 | \ 57 | \ 58 | \ 59 | \ 60 | \ 61 | \ 62 | \ 63 | \ 64 | \ 65 | \ 66 | \ 67 | \ 68 | \ 69 | \ 70 | \ 71 | \ 72 | \ 73 | \ 74 | \ 75 | \ 76 | \ 77 | \ 78 | \ 79 | \ 80 | \ 81 | \ 82 | \ 83 | \ 84 | \ 85 | \ 86 | \ 87 | \ 88 | \ 89 | \ 90 | \ 91 | \ 92 | \ 93 | \ 94 | \ 95 | \ 96 | \ 97 | \ 98 | \ 99 | \ 100 | \ 101 | \ 102 | \ 103 | \ 104 | \ 105 | \ 106 | \ 107 | \ 108 | \ 109 | \ 110 | \ 111 | \ 112 | \ 113 | \ 114 | \ 115 | \ 116 | \ 117 | \ 118 | \ 119 | \ 120 | \ 121 | \ 122 | \ 123 | \ 124 | \ 125 | \ 126 | \ 127 | \ 128 | \ 129 | \ 130 | \ 131 | \ 132 | \ 133 | \ 134 | \ 135 | \ 136 | \ 137 | \ 138 | \ 139 | \ 140 | \ 141 | \ 142 | \ 143 | \ 144 | \ 145 | \ 146 | \ 147 | \ 148 | \ 149 | \ 150 | \ 151 | \ 152 | \ 153 | \ 154 | \ 155 | \ 156 | \ 157 | \ 158 | \ 159 | \ 160 | \ 161 | \ 162 | \ 163 | \ 164 | \ 165 | \ 166 | \ 167 | \ 168 | \ 169 | \ 170 | \ 171 | \ 172 | \ 173 | \ 174 | \ 175 | \ 176 | \ 177 | \ 178 | \ 179 | \ 180 | \ 181 | \ 182 | \ 183 | \ 184 | \ 185 | \ 186 | \ 187 | \ 188 | \ 189 | \ 190 | \ 191 | \ 192 | \ 193 | \ 194 | \ 195 | \ 196 | \ 197 | \ 198 | \ 199 | \ 200 | \ 201 | \ 202 | \ 203 | \ 204 | \ 205 | \ 206 | \ 207 | \ 208 | \ 209 | \ 210 | \ 211 | \ 212 | \ 213 | \ 214 | \ 215 | \ 216 | \ 217 | \ 218 | \ 219 | \ 220 | \ 221 | \ 222 | \ 223 | \ 224 | \ 225 | \ 226 | \ 227 | \ 228 | \ 229 | \ 230 | \ 231 | \ 232 | \ 233 | \ 234 | \ 235 | \ 236 | \ 237 | \ 238 | \ 239 | \ 240 | \ 241 | \ 242 | \ 243 | \ 244 | \ 245 | \ 246 | \ 247 | \ 248 | \ 249 | \ 250 | \ 251 | \ 252 | \ 253 | \ 254 | \ 255 | \ 256 | \ 257 | \ 258 | \ 259 | \ 260 | \ 261 | \ 262 | \ 263 | \ 264 | \ 265 | \ 266 | \ 267 | \ 268 | \ 269 | \ 270 | \ 271 | \ 272 | \ 273 | \ 274 | \ 275 | \ 276 | \ 277 | \ 278 | \ 279 | \ 280 | \ 281 | \ 282 | \ 283 | \ 284 | \ 285 | \ 286 | \ 287 | \ 288 | \ 289 | \ 290 | \ 291 | \ 292 | \ 293 | \ 294 | "; 295 | 296 | #endif /* _RIGG_MONO_H */ 297 | -------------------------------------------------------------------------------- /rigg_unveil.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2024 Thomas Frohwein 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "rigg_unveil.h" 22 | #include "rigg.h" 23 | 24 | void unveil_err(const char *path, const char *permissions) { 25 | if (path == NULL && permissions == NULL) { 26 | printf("unveil: future unveil calls disabled\n"); 27 | } else { 28 | vprintf(UNVEIL_VPRINT_FMT, path, permissions); 29 | } 30 | if (unveil(path, permissions) == -1) 31 | err(1, "unveil"); 32 | } 33 | -------------------------------------------------------------------------------- /rigg_unveil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2024 Thomas Frohwein 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef _RIGG_UNVEIL_H 18 | #define _RIGG_UNVEIL_H 19 | 20 | #include "rigg.h" 21 | 22 | #define UNVEIL_VPRINT_FMT "unveil: %-32.32s \"%s\"\n" 23 | 24 | typedef struct { 25 | const char *path; 26 | const char *permissions; 27 | } unveil_pair; 28 | 29 | typedef struct { 30 | const char *file; /* program file for quirks detection */ 31 | const char *env_var; /* e.g. "HOME", set to NULL to ignore */ 32 | const char *path; /* relative to env_var if env_var is not NULL */ 33 | const char *permissions; 34 | } unveil_quirk; 35 | 36 | void unveil_err(const char *path, const char *permissions); 37 | 38 | #endif /* _RIGG_UNVEIL_H */ 39 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | # *Visible*: interact with visible part of the unveil(2)'d filesystem 2 | # *Invisible*: try to interact with invisible part of the unveil(2)'d filesystem 3 | # should fail with ENOENT if unveil(2)'d correctly 4 | # *MkdirSpecial*: Invisible directory, mkdir wrapper should return 0 anyway 5 | REGRESS_TARGETS = MonoVisible.exe MonoInvisible.exe 6 | CLEANFILES += *.exe 7 | CSCFLAGS += /nologo 8 | 9 | .SUFFIXES: .cs .exe 10 | .cs.exe: 11 | csc ${CSCFLAGS} $< 12 | rigg mono $@ 13 | 14 | .include 15 | -------------------------------------------------------------------------------- /test/MonoInvisible.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace MonoInvisible { 5 | class MI { 6 | static void Main(string[] args) { 7 | string testDir = Environment.GetEnvironmentVariable("HOME"); 8 | if (testDir == null) { 9 | Console.WriteLine("Failed to resolve $HOME"); 10 | Environment.Exit(1); 11 | } 12 | Console.WriteLine("Checking that $HOME ({0}) is invisible", testDir); 13 | 14 | /* 15 | * return 0 if doesn't exist; then it is hidden by unveil(2) 16 | * as intended 17 | */ 18 | Environment.Exit( Directory.Exists(testDir) ? 1 : 0 ); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/MonoVisible.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace MonoVisible { 5 | class MV { 6 | static void Main(string[] args) { 7 | string testDir = "/tmp"; 8 | Console.WriteLine("Checking that {0} is visible", testDir); 9 | Environment.Exit( Directory.Exists(testDir) ? 0 : 1 ); 10 | } 11 | } 12 | } 13 | --------------------------------------------------------------------------------