From fa4a70f39b0e855b0c687403638209b9b842a4a7 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 1 Nov 2009 20:10:46 +0000 Subject: [PATCH] Sort of works ... --- .gitignore | 4 ++ Makefile | 23 ++++++++++ jwrap-script | 56 +++++++++++++++++++++++ libjava-wrap | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ libjava-wrap.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++ libjwrap.c | 100 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 420 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100755 jwrap-script create mode 100644 libjava-wrap create mode 100644 libjava-wrap.c create mode 100644 libjwrap.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b1e012f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*~ +*.o +*.so +*.so.* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cce8b95 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +OPTIMISE= -O2 +LDFLAGS= -g +LIBS= -ldl -lc +CFLAGS= -g $(OPTIMISE) \ + -Wall -Wwrite-strings -Wpointer-arith -Wimplicit \ + -Wnested-externs -Wmissing-prototypes -Wstrict-prototypes +CPPFLAGS= + +MAJOR=1 +MINOR=0 +LIBCANON= libjwrap.so.$(MAJOR) +LIBTARGET= $(LIBCANON).$(MINOR) + +TARGETS= $(LIBTARGET) + +all: $(TARGETS) + + +$(LIBTARGET): libjwrap.o + ld -shared -soname $(LIBCANON) -o $@ $< $(LIBS) + +libjwrap.o: libjwrap.c + $(CC) -D_REENTRANT $(CFLAGS) $(CPPFLAGS) -c -o $@ -fPIC $< diff --git a/jwrap-script b/jwrap-script new file mode 100755 index 0000000..f6fe699 --- /dev/null +++ b/jwrap-script @@ -0,0 +1,56 @@ +#!/bin/bash +set -e$JWRAP_SCRIPT_X + +unwire () { + ldp="$LD_PRELOAD:" + ldp2='' + + while [ "x$ldp" != x ]; do + this="${ldp%%:*}" + ldp="${ldp#*:}" + case "$this" in + *libjwrap*.so.*) ;; + *) ldp2="$ldp2$this:" ;; + esac + done + + if [ "x$ldp2" != x ]; then + LD_PRELOAD="${ldp2%:}" + else + unset LD_PRELOAD + fi + + unset JWRAP_SCRIPT +} + +echo ":$*" + +path="$1"; shift +arg0="$1"; shift + +args=( "$@" ) +nargs=${#args[*]} +lastarg="${args[$(( $nargs - 1 ))]}" + +fail () { + echo >&2 "jwrap-script: $*" + exit 127 +} + +if [ x"$lastarg" = x"com.threerings.yohoho.client.YoApp" ]; then + case "$path" in + */bin/java) ;; + *) fail "unexpected path format $path" ;; + esac + [ x"$JWRAP_EXTDIR" != x ] || fail 'JWRAP_EXTDIR not set' + extdirs="$JWRAP_EXTDIR:${path%/bin/java}/lib/ext" + + set -e$JWRAP_SCRIPT_X -- \ + -Djavax.accessibility.assistive_technologies=com.tedpearson.ypp.market.MarketUploader \ + -Djava.ext.dirs="$extdirs" \ + "$@" + + unwire +fi + +exec -a "$arg0" /dev/jwrap/bypass "$path" "$@" diff --git a/libjava-wrap b/libjava-wrap new file mode 100644 index 0000000..9b904ed --- /dev/null +++ b/libjava-wrap @@ -0,0 +1,119 @@ +/**/ + +#define _GNU_SOURCE +#include +#include +#include + +#define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1) +#define STDERRSTR_STRING(m) write(2,m,strlen(m)) + +static anyfn_type *find_any(const char *name) { + static const char *dlerr; + anyfn_type *kv; + + kv= dlsym(RTLD_NEXT,name); if (kv) return kv; + dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason"; + STDERRSTR_CONST("pctb-preload-wrap: error finding original version of "); + STDERRSTR_STRING(name); + STDERRSTR_CONST(": "); + STDERRSTR_STRING(dlerr); + STDERRSTR_STRING("\n"); + errno= ENOSYS; + return 0; +} + +typedef int +execvefn_type(const char *path, char *const argv[], char *const envp[]); + +static execvefn_type find_execve, *old_execve= find_execve; + +static int find_execve(const char *path, + char *const argv[], char *const envp[]) { + anyfn_type *anyfn; + anyfn= find_any("execve"); if (!anyfn) return -1; + old_execve= (execvefn_type*)anyfn; + return old_execve(path, argv, envp); +} + +static const char javatail[]= "/bin/java"; + +int execve(const char *path, char *const argv[], char *const envp[]) { + int pathlen= strlen(path); + if (pathlen < (sizeof(path2extdir_rm)-1) || + strcmp(javatail, path + pathlen-(sizeof(path2extdir_rm)-1))) + old_execve(opath, oargv, oenvp); + + + + + int oargc; + + + + xassert(opathlen >= + + + for (oargc=0; oargv[oargc]; oargc++); + xassert(oargc); + if (strcmp(oargv[oargc-1], "com.threerings.yohoho.client.YoApp")) + + /* Remove ourselves from LD_PRELOAD */ + int ipreloadenv=-1; + const char ldpreload[]= "LD_PRELOAD="; + for (oenvc=0; oenvp[oenvc]; oenvc++) { + if (memcmp(oenvp[oenvc], ldpreload, sizeof(ldpreload)-1)) continue; + xassert(ipreloadenv==-1); + ipreloadenv= oenvc; + } + xassert(ipreloadenv>=0); + xassert(!strchr(':',oenvp[ipreloadenv])); + + + int nargc= oargc+2; + char **nargv= xmalloc(sizeof(*nargv) * (nargc+1)); + + /* Add argument for accessibility assistive tech. */ + int iargc= oargc-1; + memcpy(nargv, oargv, iargc); + nargv[iargc++]= "-Djavax.accessibility.assistive_technologies=" + "com.tedpearson.ypp.market.MarketUploader"; + + /* Calculate and add argument for ext dirs containing our jars */ + const char *nextdir; + xassert((nextdir= getenv("JPCTB_EXTDIR"))); + int nextdirlen= strlen(nextdir); + + int njvmextdirbaselen= opathlen-sizeof(path2extdir_rm)-1); + xassert(!strcmp(path2extdir_rm, opath+njvmextdirbaselen); + + const char path2extdir_pfx[]= "-Djava.ext.dirs="; + const char path2extdir_sfx[]= "/lib/ext"; + +#define STRS(STR,DL) \ + STR( path2extdir_pfx, sizeof(path2extdir_pfx)-1 ) DL \ + STR( nextdir, nextdirlen ) DL \ + STR( ":", 1 ) DL \ + STR( opath, njvmextdirbaselen ) DL \ + STR( path2extdir_sfx, sizeof(path2extdir_sfx)-1 ) DL \ + STR( "", 1 ) + +#define STR_LEN(str,len) (len) + char *nextdirarg= xmalloc(STRS(STR_LEN, +)); + char *p= nextdirarg; + +#define STR_ADD(str,len) \ + memcpy(p,(str),(len)); p += (len); + STRS(STR_ADD, ;); + + nargv[iargc++]= nextdirarg; + + /* Remaining argument: the class */ + nargv[iargc++]= oargv[oargc-1]; + + + + + + if (arg +} diff --git a/libjava-wrap.c b/libjava-wrap.c new file mode 100644 index 0000000..4bafa41 --- /dev/null +++ b/libjava-wrap.c @@ -0,0 +1,118 @@ +/**/ + +#define _GNU_SOURCE +#include +#include +#include + +#define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1) +#define STDERRSTR_STRING(m) write(2,m,strlen(m)) + +static anyfn_type *find_any(const char *name) { + static const char *dlerr; + anyfn_type *kv; + + kv= dlsym(RTLD_NEXT,name); if (kv) return kv; + dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason"; + STDERRSTR_CONST("pctb-preload-wrap: error finding original version of "); + STDERRSTR_STRING(name); + STDERRSTR_CONST(": "); + STDERRSTR_STRING(dlerr); + STDERRSTR_STRING("\n"); + errno= ENOSYS; + return 0; +} + +typedef int +execvefn_type(const char *path, char *const argv[], char *const envp[]); + +static execvefn_type find_execve, *old_execve= find_execve; + +static int find_execve(const char *path, + char *const argv[], char *const envp[]) { + anyfn_type *anyfn; + anyfn= find_any("execve"); if (!anyfn) return -1; + old_execve= (execvefn_type*)anyfn; + return old_execve(path, argv, envp); +} + +static const char javatail[]= "/bin/java"; + +int execve(const char *path, char *const argv[], char *const envp[]) { + int pathlen= strlen(path); + if (pathlen < (sizeof(path2extdir_rm)-1) || + strcmp(javatail, path + pathlen-(sizeof(path2extdir_rm)-1))) + old_execve(opath, oargv, oenvp); + + + + + int oargc; + + + + xassert(opathlen >= + + + for (oargc=0; oargv[oargc]; oargc++); + xassert(oargc); + if (strcmp(oargv[oargc-1], "com.threerings.yohoho.client.YoApp")) + + /* Remove ourselves from LD_PRELOAD */ + int ipreloadenv=-1; + const char ldpreload[]= "LD_PRELOAD="; + for (oenvc=0; oenvp[oenvc]; oenvc++) { + if (memcmp(oenvp[oenvc], ldpreload, sizeof(ldpreload)-1)) continue; + xassert(ipreloadenv==-1); + ipreloadenv= oenvc; + } + xassert(ipreloadenv>=0); + xassert(!strchr(':',oenvp[ipreloadenv])); + + + int nargc= oargc+2; + char **nargv= xmalloc(sizeof(*nargv) * (nargc+1)); + + /* Add argument for accessibility assistive tech. */ + int iargc= oargc-1; + memcpy(nargv, oargv, iargc); + nargv[iargc++]= " + ""; + + /* Calculate and add argument for ext dirs containing our jars */ + const char *nextdir; + xassert((nextdir= getenv("JPCTB_EXTDIR"))); + int nextdirlen= strlen(nextdir); + + int njvmextdirbaselen= opathlen-sizeof(path2extdir_rm)-1); + xassert(!strcmp(path2extdir_rm, opath+njvmextdirbaselen); + + const char path2extdir_pfx[]= " + +#define STRS(STR,DL) \ + STR( path2extdir_pfx, sizeof(path2extdir_pfx)-1 ) DL \ + STR( nextdir, nextdirlen ) DL \ + STR( ":", 1 ) DL \ + STR( opath, njvmextdirbaselen ) DL \ + STR( path2extdir_sfx, sizeof(path2extdir_sfx)-1 ) DL \ + STR( "", 1 ) + +#define STR_LEN(str,len) (len) + char *nextdirarg= xmalloc(STRS(STR_LEN, +)); + char *p= nextdirarg; + +#define STR_ADD(str,len) \ + memcpy(p,(str),(len)); p += (len); + STRS(STR_ADD, ;); + + nargv[iargc++]= nextdirarg; + + /* Remaining argument: the class */ + nargv[iargc++]= oargv[oargc-1]; + + + + + + if (arg +} diff --git a/libjwrap.c b/libjwrap.c new file mode 100644 index 0000000..b74a99a --- /dev/null +++ b/libjwrap.c @@ -0,0 +1,100 @@ +/**/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1) +#define STDERRSTR_STRING(m) write(2,m,strlen(m)) + +#define QUIS "libjwrap" + +typedef void anyfn_type(void); +typedef int +execvefn_type(const char *path, char *const argv[], char *const envp[]); + +static execvefn_type find_execve, *old_execve= find_execve; + +static anyfn_type *find_any(const char *name) { + static const char *dlerr; + anyfn_type *kv; + + kv= dlsym(RTLD_NEXT,name); if (kv) return kv; + dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason"; + STDERRSTR_CONST(QUIS ": error finding original version of "); + STDERRSTR_STRING(name); + STDERRSTR_CONST(": "); + STDERRSTR_STRING(dlerr); + STDERRSTR_CONST("\n"); + errno= ENOSYS; + return 0; +} + +static int find_execve(const char *path, + char *const argv[], char *const envp[]) { + anyfn_type *anyfn; + anyfn= find_any("execve"); if (!anyfn) return -1; + old_execve= (execvefn_type*)anyfn; + return old_execve(path, argv, envp); +} + +static const char javatail[]= "/bin/java"; + +int execve(const char *path, char *const oargv[], char *const envp[]) { + int oargc; + for (oargc=0; oargv[oargc]; oargc++); + + if (!strcmp(path,"/dev/jwrap/bypass")) { + //STDERRSTR_CONST(QUIS ": bypass\n"); + int nargc= oargc-1; + char **nargv= malloc(sizeof(*nargv) * nargc); if (!nargv) return -1; + nargv[0]= oargv[0]; + memcpy(nargv+1, oargv+2, sizeof(*nargv) * nargc-1); + return old_execve(oargv[1], nargv, envp); + } + + int pathlen= strlen(path); + if (!oargc || + pathlen < (sizeof(javatail)-1) || + strcmp(javatail, path + pathlen-(sizeof(javatail)-1))) { + //STDERRSTR_CONST(QUIS ": non-java\n"); + return old_execve(path, oargv, envp); + } + + //STDERRSTR_CONST(QUIS ": ours\n"); + + struct stat stab; + if (stat(path,&stab)) return -1; + + int nargc= oargc+2; + char **nargv= malloc(sizeof(*nargv) * nargc); if (!nargv) return -1; + + const char *jwrap_script= getenv("JWRAP_SCRIPT"); + if (!jwrap_script) { + STDERRSTR_CONST(QUIS ": no JWRAP_SCRIPT specified!\n"); + errno= ENOENT; + return -1; + } + + nargv[0]= (char*)jwrap_script; + nargv[1]= (char*)path; + memcpy(nargv+2, oargv, sizeof(*nargv) * (oargc+1)); + + old_execve(nargv[0], nargv, envp); + int e= errno; + + const char *errstr= strerror(e); + STDERRSTR_CONST(QUIS ": failed to execute "); + STDERRSTR_STRING(jwrap_script); + STDERRSTR_CONST(": "); + STDERRSTR_STRING(errstr); + STDERRSTR_CONST("\n"); + + errno= e; + return -1; +} -- 2.30.2