Created
April 22, 2012 03:30
-
-
Save jyio/2446834 to your computer and use it in GitHub Desktop.
PengDroid: a healthy fusion of Debian and Android
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
set -e -x | |
export PATH=$PATH:/usr/local/sbin:/usr/sbin:/sbin | |
mkdir -p /usr/share/man/man1 | |
/var/lib/dpkg/info/dash.preinst install || true | |
dpkg --configure -a | |
ln -sf update-rc.d-insserv /usr/sbin/update-rc.d | |
dpkg --clear-selections | |
dpkg --set-selections < /selections | |
apt-get -u dselect-upgrade --purge | |
ln -sf update-rc.d-insserv /usr/sbin/update-rc.d | |
ln -sf /bin/sh /bin/bash | |
echo BotBrew > /etc/debian_chroot | |
mkdir /android | |
ln -s /android/system /system | |
ln -s /android/data /data | |
ln -s /android/cache /cache | |
rm /config.sh | |
rm /selections | |
rm /usr/bin/qemu-arm-static |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <libgen.h> | |
#include <getopt.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <alloca.h> | |
#include <malloc.h> | |
#include <unistd.h> | |
#include <sched.h> | |
#include <errno.h> | |
#include <sys/stat.h> | |
#include <sys/mount.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include "strnstr.h" | |
#define ENV_PATH "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/usr/libexec/busybox" | |
struct config { | |
char *target; | |
char *cwd; | |
char *const *argv; | |
}; | |
struct mountspec { | |
char *src; | |
char *dst; | |
char *type; | |
unsigned long flags; | |
void *data; | |
unsigned long remount_flags; | |
}; | |
static struct mountspec foreign_mounts[] = { | |
{NULL,"/proc","proc",0,NULL,0}, | |
{"/dev","/dev",NULL,MS_BIND,NULL,0}, | |
{"/dev/pts","/dev/pts",NULL,MS_BIND,NULL,0}, | |
{NULL,"/sys","sysfs",0,NULL,0}, | |
{NULL,"/android","tmpfs",MS_NODEV|MS_NOEXEC|MS_NOATIME,"size=1M,mode=0755",0}, | |
{"/cache","/android/cache",NULL,MS_BIND,NULL,0}, | |
{"/data","/android/data",NULL,MS_BIND,NULL,0}, | |
{"/emmc","/android/emmc",NULL,MS_BIND,NULL,0}, | |
{"/sd-ext","/android/sd-ext",NULL,MS_BIND,NULL,0}, | |
{"/sdcard","/android/sdcard",NULL,MS_BIND,NULL,0}, | |
{"/system","/android/system",NULL,MS_BIND,NULL,MS_REMOUNT|MS_NODEV|MS_NOATIME}, | |
{"/usbdisk","/android/usbdisk",NULL,MS_BIND,NULL,0}, | |
{"/system/xbin","/android/system/xbin",NULL,MS_BIND,NULL,MS_REMOUNT|MS_NODEV|MS_NOATIME} | |
}; | |
static int n_foreign_mounts = sizeof(foreign_mounts)/sizeof(foreign_mounts[0]); | |
static void usage(char *progname) { | |
fprintf(stderr, | |
"Usage: %s [options] [--] [<command>...]\n" | |
"\n" | |
"Available options:\n" | |
"\t-d <directory>\t| --dir=<directory>\tSpecify chroot directory\n", | |
progname); | |
exit(EXIT_FAILURE); | |
} | |
static void privdrop(void) { | |
gid_t gid = getgid(); | |
uid_t uid = getuid(); | |
setgroups(1,&gid); | |
#ifdef linux | |
setregid(gid,gid); | |
setreuid(uid,uid); | |
#else | |
setegid(gid); | |
setgid(gid); | |
seteuid(uid); | |
setuid(uid); | |
#endif | |
} | |
static int main_clone(struct config *config) { | |
char *initsh = alloca(snprintf(NULL,0,"%s/init.sh",config->target)+1); | |
sprintf(initsh,"%s/init.sh",config->target); | |
char cwd[PATH_MAX]; | |
if(getcwd(cwd,sizeof(cwd)) == NULL) { | |
fprintf(stderr,"whoops: cannot get working directory\n"); | |
return EXIT_FAILURE; | |
} | |
if(chdir(config->target)) { | |
fprintf(stderr,"whoops: cannot chdir to namespace\n"); | |
return EXIT_FAILURE; | |
} | |
size_t target_len = strlen(config->target); | |
int i; | |
for(i = 0; i < n_foreign_mounts; i++) { | |
struct mountspec m = foreign_mounts[i]; | |
size_t dst_len = strlen(m.dst); | |
char *dst = malloc(target_len+dst_len+1); | |
memcpy(dst,config->target,target_len); | |
memcpy(dst+target_len,m.dst,dst_len+1); // includes null terminator | |
mkdir(dst,0755); | |
if(mount(m.src,dst,m.type,m.flags,m.data)) rmdir(dst); | |
else if(m.remount_flags) mount(dst,dst,NULL,m.remount_flags|MS_REMOUNT,NULL); | |
free(dst); | |
} | |
if(chroot(".")) { | |
fprintf(stderr,"whoops: cannot chroot\n"); | |
return EXIT_FAILURE; | |
} | |
if((chdir(cwd))&&(chdir("/"))) { | |
fprintf(stderr,"whoops: cannot chdir to chroot\n"); | |
return EXIT_FAILURE; | |
} | |
privdrop(); | |
char *env_path = getenv("PATH"); | |
if((env_path)&&(env_path[0])) { | |
size_t env_path_len = strlen(env_path); | |
char *newpath = malloc(sizeof(ENV_PATH)+env_path_len); | |
char *append = strstr(env_path,"::"); | |
if(append) { // break string at :: and insert | |
append++; | |
size_t prepend_len = append-env_path; | |
memcpy(newpath,env_path,prepend_len); | |
memcpy(newpath+prepend_len,ENV_PATH,sizeof(ENV_PATH)-1); | |
memcpy(newpath+prepend_len+sizeof(ENV_PATH)-1,append,env_path_len-prepend_len+1); | |
} else { | |
memcpy(newpath,ENV_PATH":",sizeof(ENV_PATH":")-1); | |
memcpy(newpath+sizeof(ENV_PATH":")-1,env_path,env_path_len+1); // includes null terminator | |
} | |
setenv("PATH",newpath,1); | |
free(newpath); | |
} else setenv("PATH",ENV_PATH":/android/sbin:/system/sbin:/system/bin:/system/xbin",1); | |
if(config->argv == NULL) { | |
char *argv0[2]; | |
argv0[0] = "/init.sh"; | |
argv0[1] = 0; | |
config->argv = (char**)&argv0; | |
} | |
if(execvp(config->argv[0],config->argv)) { | |
int i = 1; | |
fprintf(stderr,"whoops: cannot run `%s",config->argv[0]); | |
while(config->argv[i]) fprintf(stderr," %s",config->argv[i++]); | |
fprintf(stderr,"'\n"); | |
return errno; | |
} | |
return 0; // wtf | |
} | |
int main(int argc, char *argv[]) { | |
struct config config; | |
struct stat st; | |
char apath[PATH_MAX]; | |
// get absolute path | |
config.target = realpath(dirname(argv[0]),apath); | |
uid_t uid = getuid(); | |
int c; | |
while(1) { | |
static struct option long_options[] = { | |
{"dir",required_argument,0,'d'}, | |
{0,0,0,0} | |
}; | |
int option_index = 0; | |
c = getopt_long(argc,argv,"d:",long_options,&option_index); | |
if(c == -1) break; | |
switch(c) { | |
case 'd': | |
// prevent privilege escalation: only superuser can chroot to arbitrary directories | |
if(uid) { | |
fprintf(stderr,"whoops: --dir is only available for uid=0\n"); | |
return EXIT_FAILURE; | |
} | |
config.target = realpath(optarg,apath); | |
break; | |
default: | |
usage(argv[0]); | |
} | |
} | |
config.argv = (optind==argc)?NULL:(argv+optind); | |
// prevent privilege escalation: fail if link/symlink is not owned by superuser | |
if(uid) { | |
if(lstat(argv[0],&st)) { | |
fprintf(stderr,"whoops: cannot stat `%s'\n",argv[0]); | |
return EXIT_FAILURE; | |
} | |
if(st.st_uid) { | |
fprintf(stderr,"whoops: `%s' is not owned by uid=0\n",argv[0]); | |
return EXIT_FAILURE; | |
} | |
} | |
// check if directory exists | |
if((stat(config.target,&st))||(!S_ISDIR(st.st_mode))) { | |
fprintf(stderr,"whoops: `%s' is not a directory\n",config.target); | |
return EXIT_FAILURE; | |
} | |
if((st.st_uid)||(st.st_gid)) chown(config.target,0,0); | |
if((st.st_mode&S_IWGRP)||(st.st_mode&S_IWOTH)) chmod(config.target,0755); | |
// check if directory mounted | |
FILE *fp; | |
char *haystack; | |
size_t len; | |
size_t target_len = strlen(config.target); | |
char *needle = malloc(target_len+3); | |
needle[0] = needle[target_len+1] = ' '; | |
memcpy(needle+1,config.target,target_len+1); // includes null terminator | |
int mounted = 0; | |
if(fp = fopen("/proc/self/mounts","r")) while(haystack = fgetln(fp,&len)) if(strnstr(haystack,needle,len)) { | |
mounted = 1; | |
break; | |
} | |
free(needle); | |
if(!mounted) { | |
if(geteuid()) { | |
fprintf(stderr,"whoops: superuser privileges required for first invocation of `%s'\n",argv[0]); | |
return EXIT_FAILURE; | |
} | |
mount(config.target,config.target,NULL,MS_BIND,NULL); | |
mount(config.target,config.target,NULL,MS_REMOUNT|MS_NODEV|MS_NOATIME,NULL); | |
if(!stat(argv[0],&st)) { | |
// setuid | |
if((st.st_uid)||(st.st_gid)) chown(argv[0],0,0); | |
if((st.st_mode&S_IWGRP)||(st.st_mode&S_IWOTH)||!(st.st_mode&S_ISUID)) chmod(argv[0],04755); | |
} | |
} | |
// clone with new namespace | |
long stacksz = sysconf(_SC_PAGESIZE); | |
void *stack = alloca(stacksz)+stacksz; | |
pid_t pid = clone(main_clone,stack,SIGCHLD|CLONE_NEWNS|CLONE_FILES,(void*)&config); | |
if(pid < 0) { | |
fprintf(stderr,"whoops: cannot clone\n"); | |
return EXIT_FAILURE; | |
} else { | |
int ret; | |
privdrop(); | |
while((waitpid(pid,&ret,0)<0)&&(errno == EINTR)); | |
return WIFEXITED(ret)?WEXITSTATUS(ret):EXIT_FAILURE; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/system/bin/sh | |
case "$0" in | |
/init.sh) | |
exec /system/bin/sh | |
;; | |
esac |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[General] | |
arch = armel | |
directory = ./pengdroid/ | |
cleanup = true | |
noauth = true | |
unpack = true | |
debootstrap = Grip | |
aptsources = Grip | |
setupscript= ./setup.sh | |
configscript= ./config.sh | |
[Grip] | |
keyring = emdebian-archive-keyring | |
source = http://www.emdebian.org/grip | |
suite = squeeze |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apt install | |
coreutils install | |
dash install | |
debconf install | |
debconf-i18n install | |
debian-archive-keyring install | |
debianutils install | |
dpkg install | |
emdebian-archive-keyring install | |
findutils install | |
gcc-4.4-base install | |
gnupg install | |
gpgv install | |
insserv install | |
libacl1 install | |
libattr1 install | |
libbz2-1.0 install | |
libc-bin install | |
libc6 install | |
libdb4.8 install | |
libgcc1 install | |
liblocale-gettext-perl install | |
liblzma2 install | |
libncurses5 install | |
libpam-modules install | |
libpam-runtime install | |
libpam0g install | |
libreadline6 install | |
libselinux1 install | |
libstdc++6 install | |
libtext-charwidth-perl install | |
libtext-iconv-perl install | |
libtext-wrapi18n-perl install | |
libusb-0.1-4 install | |
mawk install | |
passwd install | |
perl-base install | |
readline-common install | |
sed install | |
sensible-utils install | |
xz-utils install | |
zlib1g install |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
set -e -x | |
# pass path to the root. Don't let it run without one as it will break your system | |
if [ "" = "$1" ] ; then | |
echo "You need to specify a path to the target rootfs" | |
else | |
if [ -e "$1" ] ; then | |
ROOTFS="$1" | |
else | |
echo "Root dir $ROOTFS not found" | |
fi | |
fi | |
if [ "/" = "ROOTFS" ] ; then echo "Refusing to change your build system's files" ; fi | |
# set hostname | |
echo botbrew > $ROOTFS/etc/hostname | |
echo "127.0.0.1 localhost.localdomain localhost" > ${ROOTFS}/etc/hosts | |
echo "127.0.1.1 botbrew botbrew" >> ${ROOTFS}/etc/hosts | |
echo "nameserver 8.8.8.8" > ${ROOTFS}/etc/resolv.conf | |
echo "nameserver 8.8.4.4" >> ${ROOTFS}/etc/resolv.conf | |
cp /usr/bin/qemu-arm-static ${ROOTFS}/usr/bin/ | |
cp selections ${ROOTFS}/ | |
cp init.sh ${ROOTFS}/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*- | |
* Copyright (c) 2001 Mike Barcroft <[email protected]> | |
* Copyright (c) 1990, 1993 | |
* The Regents of the University of California. All rights reserved. | |
* | |
* This code is derived from software contributed to Berkeley by | |
* Chris Torek. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* 3. All advertising materials mentioning features or use of this software | |
* must display the following acknowledgement: | |
* This product includes software developed by the University of | |
* California, Berkeley and its contributors. | |
* 4. Neither the name of the University nor the names of its contributors | |
* may be used to endorse or promote products derived from this software | |
* without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
* SUCH DAMAGE. | |
*/ | |
#if defined(LIBC_SCCS) && !defined(lint) | |
static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93"; | |
#endif /* LIBC_SCCS and not lint */ | |
#include <sys/cdefs.h> | |
__FBSDID("$FreeBSD: src/lib/libc/string/strnstr.c,v 1.2.2.1 2001/12/09 06:50:03 mike Exp $"); | |
#include <string.h> | |
/* | |
* Find the first occurrence of find in s, where the search is limited to the | |
* first slen characters of s. | |
*/ | |
char * | |
strnstr(s, find, slen) | |
const char *s; | |
const char *find; | |
size_t slen; | |
{ | |
char c, sc; | |
size_t len; | |
if ((c = *find++) != '\0') { | |
len = strlen(find); | |
do { | |
do { | |
if ((sc = *s++) == '\0' || slen-- < 1) | |
return (NULL); | |
} while (sc != c); | |
if (len > slen) | |
return (NULL); | |
} while (strncmp(s, find, len) != 0); | |
s--; | |
} | |
return ((char *)s); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef STRNSTR_H | |
#define STRNSTR_H | |
char *strnstr(const char *s, const char *find, size_t slen); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment