How To HOWTO fix stock busybox/sed insert command on your R7800/R9000/etc

  • ATTENTION! As of November 1, 2020, you are not able to reply to threads 6 months after the thread is opened if there are more than 500 posts in the thread.
    Threads will not be locked, so posts may still be edited by their authors.
    Just start a new thread on the topic to post if you get an error message when trying to reply to a thread.

arabesc

Occasional Visitor
During NG firmware script patching research I've realized that stock busybox/sed tool has a bug - the insert command doesn't work properly.
Here is a test:
# printf "1\n3" | /bin/sed '/3/i 2' | hexdump -C
The buggy output is:
00000000 31 0a 32 01 33 |1.2.3|
And the expected output is:
00000000 31 0a 32 0a 33 |1.2.3|

The issue seems to be not critical for the stock firmware scripts because they don't use the sed insert command.
The bug has been fixed in the commit 826c85f3828c30b772d307c6b60ff3be744cecc2 to the busybox repo but NG firmware uses an older version without the fix.
There is no need to fix the bug if you are not going to use the sed insert command!

I've made a small binary patch for the /bin/busybox that as I hope fixes the issue:
0120a0e3081099e5 -> 0a20a0e3081099e5
It works for a current and a few previous Voxel's firmware versions.

The patch can be applied with the following command sequence:
# hexdump -ve '1/1 "%.2x"' /bin/busybox | sed 's/0120a0e3081099e5/0a20a0e3081099e5/' | sed 's/\([0-9a-f]\{1,60\}\)/\1\n/g' | xxd -r -ps > busybox
I haven't found a way to apply a binary patch in the stock firmware environment without additional dependencies, so the method requires the xxd tool from the Entware.

I've written a more advanced script to patch busybox, it makes some additional checks before and after patching. The script may require some minor adaptation to your environment and then the call to the script may be added to the /mnt/optware/autorun/scripts/post-mount.sh script to automatically patch /bin/busybox after every firmware update.
Bash:
#!/bin/sh

BASE_PATH="/tmp/mnt/optware/config"
INIT_LOG="$BASE_PATH/init.log"

XXD_SYS="/opt/bin/xxd"
BUSYBOX_SYS="/bin/busybox"
BUSYBOX_BAK="$BASE_PATH/scripts/backup/busybox.bak"
BUSYBOX_NEW="$BASE_PATH/scripts/backup/busybox.new"
SED_SYS="/bin/sed"
SED_TEST="$BASE_PATH/scripts/backup/sed"

/bin/echo "patch-busybox.sh" >> "$INIT_LOG"

if [ ! -x "$XXD_SYS" ]; then
    /bin/echo "There is no $XXD_SYS" >> "$INIT_LOG"
    exit 1
fi

if [ ! -x "$BUSYBOX_SYS" ]; then
    /bin/echo "There is no $BUSYBOX_SYS" >> "$INIT_LOG";
    exit 1
fi

if [ ! -h "$SED_SYS" ]; then
    /bin/echo "There is no $SED_SYS" >> "$INIT_LOG"
    exit 1
fi

result=`/usr/bin/printf "1\n3" | "$SED_SYS" '/3/i 2' | "$XXD_SYS" -p -seek 3 -l 1`
if [ "$result" == "0a" ]; then
    /bin/echo "Busybox is already patched" >> "$INIT_LOG"
    exit 0
fi

if ! /bin/cp -fp "$BUSYBOX_SYS" "$BUSYBOX_BAK"; then
    /bin/echo "Failed to copy $BUSYBOX_SYS to $BUSYBOX_BAK" >> "$INIT_LOG"
    exit 1
fi

if ! /usr/bin/diff "$BUSYBOX_SYS" "$BUSYBOX_BAK" > /dev/null 2>&1; then
    /bin/echo "$BUSYBOX_BAK is corrupted" >> "$INIT_LOG"
    /bin/rm -f "$BUSYBOX_BAK"
    exit 1
fi

/usr/bin/hexdump -ve '1/1 "%.2x"' $BUSYBOX_BAK | $SED_SYS 's/0120a0e3081099e5/0a20a0e3081099e5/' | $SED_SYS 's/\([0-9a-f]\{1,60\}\)/\1\n/g' | $XXD_SYS -r -ps > $BUSYBOX_NEW

if [ ! $? ] || [ ! -f "$BUSYBOX_NEW" ]; then
    /bin/echo "Failed to patch $BUSYBOX_BAK" >> "$INIT_LOG"
    /bin/rm -f "$BUSYBOX_NEW" "$BUSYBOX_BAK"
    exit 1
fi

if ! /bin/chmod 755 "$BUSYBOX_NEW"; then
    /bin/echo "Failed to set access mode to $BUSYBOX_BAK" >> "$INIT_LOG"
    /bin/rm -f "$BUSYBOX_NEW" "$BUSYBOX_BAK"
    exit 1
fi

if ! /bin/ln -sf "$BUSYBOX_NEW" "$SED_TEST"; then
    /bin/echo "Failed to link $BUSYBOX_BAK to $SED_TEST" >> "$INIT_LOG"
    /bin/rm -f "$SED_TEST" "$BUSYBOX_NEW" "$BUSYBOX_BAK"
    exit 1
fi

result=`/usr/bin/printf "1\n3" | "$SED_TEST" '/3/i 2' | "$XXD_SYS" -p -seek 3 -l 1`
if [ "$result" != "0a" ]; then
    /bin/echo "Busybox patch doesn't work" >> "$INIT_LOG"
    /bin/rm -f "$SED_TEST" "$BUSYBOX_NEW" "$BUSYBOX_BAK"
    exit 1
fi

if ! /bin/cp -fp "$BUSYBOX_NEW" "$BUSYBOX_SYS"; then
    /bin/echo "Failed to copy $BUSYBOX_NEW to $BUSYBOX_SYS" >> "$INIT_LOG"
    /bin/rm -f "$SED_TEST" "$BUSYBOX_NEW" "$BUSYBOX_BAK"
    exit 1
fi

/bin/rm -f "$SED_TEST" "$BUSYBOX_NEW"

/bin/echo "Busybox has been successfully patched" >> "$INIT_LOG"

exit 0
 

kamoj

Very Senior Member
Excellent job and tutorial!
I couldn't resist to do the patch with existing tools: ;)
Bash:
cd /tmp
dd if=/bin/busybox bs=1 skip=0 count=211696 of=busybox.1
echo -n "x" | tr "x" "\x0A" >busybox.2
dd if=/bin/busybox bs=1 skip=211697 count=381940 of=busybox.3
cat busybox.1 busybox.2 busybox.3 >busybox.new
chmod +x busybox.new
\mv -f busybox.new /bin/busybox
cd -

Or a more educational and generic way to work for other busybox versions than the latest:
Bash:
# Setup
tmpdir="/tmp"
file="/bin/busybox"
filename="$(basename "$file")"
filesize="$(ls -al "$file"|awk '{print $5}')"
offset_to_patch="$(hexdump -ve '1/1 "%.2x"' "$file" | awk -F "0120a0e3081099e5" '{print $1}' | wc -c | awk '{print -1+$1/2}')"

# Check if sed is already working or not:
if printf "1\n3" | "$file" sed '/3/i 2' | hexdump -C | grep "31 0a 32 01 33"; then
   echo "sed command fails, trying to patch $file"
elif printf "1\n3" | "$file" sed '/3/i 2' | hexdump -C | grep "31 0a 32 0a 33"; then
   echo "sed command already working. Restoring original $file, and trying to patch!"
   \cp -fp /rom$file $file
fi

# Do the patching to a copy of busybox in /tmp:
dd if="$file" bs=1 skip=0 count="$offset_to_patch" of="$tmpdir"/"$filename".1
echo -n "x" | tr "x" "\x0A" >"$tmpdir"/"$filename".2
dd if="$file" bs=1 skip="$((offset_to_patch+1))" count="$((filesize-$offset_to_patch-1))" of="$tmpdir"/"$filename".3
cat "$tmpdir"/"$filename".1 "$tmpdir"/"$filename".2 "$tmpdir"/"$filename".3 >"$tmpdir"/"$filename".new

# Make the new busybox executable:
chmod +x "$tmpdir"/"$filename".new

# Test if the new sed is working:
if printf "1\n3" | "$tmpdir"/"$filename".new sed '/3/i 2' | hexdump -C | grep "31 0a 32 0a 33"; then
   echo "Patch succeeded."
   \mv -f "$tmpdir"/"$filename".new "$file"
   echo "To restore original: \cp -p /rom$file $file"
else
   echo "Patch failed. Nothing is changed"
fi

# Clean up:
\rm -f "$tmpdir"/"$filename".*
 
Last edited:

L&LD

Part of the Furniture

Voxel

Very Senior Member
As I already wrote to @arabesc I am a bit conservative with some from packages used by NG/DNI. The reason is: yeah, there are bugs in some packages. But they are known. If I fix/renew e.g. stone age busybox I have also check a lot of e.g. QCA scripts taken from the stock version... After month or so somebody will write that there are issues in new version, and there will be a headache for me to trace this...

Really, there is very fresh version of busybox from Entware. Everybody is free to use it. Or e.g. "classic" sed https://www.voxel-firmware.com/Downloads/Voxel/Entware/Entware-3x-Voxel/sed_4.8-3_cortex-a15-3x.ipk.

Anyway, thanks to @arabesc and all the rest who wants to improve my build :)

Voxel.
 

Latest threads

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top