HTTPプロトコル(302ステータス)

友達から質問を受けて少し勉強しました。ソケット通信は最近あんまりつかってなかったので再度勉強した。

ソケット通信でサーバ側でやることは

  1. ソケットの生成
  2. bind
  3. listen
  4. acept
  5. 送受信処理

です。

こんな感じのソース書いた。

#-*- coding: utf-8 -*-
import socket
import threading

class ClientThread(threading.Thread):
	def __init__(self, soc):
		super(ClientThread, self).__init__()
		self.soc = soc

	def run(self):
		self.recv()
		self.response()

	###################################
	# 受信データを切れ目まで読み飛ばす
	def recv(self):
		while True:
			data = self.soc.recv(1024)
			if ((data == '\r\n') or  (data == '\n)')):
				break;
			if ('\r\n\r\n' in data):
				break
#			print "server:receive '%s'" % data


	###################################
	# 302レスポンスをかえす
	def response(self):
		self.soc.send("HTTP/1.1 302 Found" + "\r\n")
		self.soc.send("Location: http://www.google.co.jp/" + "\r\n")
		self.soc.send("\r\n")



class Server(object):
	def __init__(self, host, port):
		self.host = host
		self.port = port

	def createServerSocket(self):
		self.server_soc = socket.socket(
						socket.AF_INET,
						socket.SOCK_STREAM)
		self.server_soc.setsockopt(
					socket.SOL_SOCKET,
					socket.SO_REUSEADDR, 1)
		self.server_soc.bind((self.host, self.port))
		print(u"Bind %s:%d" %(self.host, self.port))

	def acceptLoop(self):
		self.server_soc.listen(5)
		(client_soc, client_address) = self.server_soc.accept()
		clientThread = ClientThread(client_soc)
		clientThread.start()


if __name__ == '__main__':
	server = Server('localhost', 60000)
	server.createServerSocket()
	server.acceptLoop()

もう少しちゃんと改造すれば、簡易HTTPサーバとかにできるかも。

D_FORTIFY_SOURCEを使う

これもバッファーオーバーフロー検出に関するお話。
gcc4からの機能です。

使い方 (o1以上の最適化オプションをつける)

gcc -O1 -D_FORTIFY_SOURCE=1 foo.c

検出時は、下記のいずれか

  1. コンパイル時
  2. 実行時

これの機能のすごいとこは、リリースビルドで使えるということ。

  • gオプションがいらないので、リリースするモジュールにも積極的に使えるということ。
#include <string.h>
static char buf[6];
int main(int argc, char** argv)
{
    strcpy(buf, argv[1]);
    return 0;
}    

こんなソースを実行すると下記の感じになる。

======= Memory map: ========
08048000-08049000 r-xp 00000000 08:01 10888991   /home/hidekazu/src/c/tmp/a.out
08049000-0804a000 rw-p 00000000 08:01 10888991   /home/hidekazu/src/c/tmp/a.out
08d3a000-08d5b000 rw-p 00000000 00:00 0          [heap]
46e97000-46eb6000 r-xp 00000000 08:01 9179830    /usr/lib/ld-2.15.so
46eb6000-46eb7000 r--p 0001e000 08:01 9179830    /usr/lib/ld-2.15.so
46eb7000-46eb8000 rw-p 0001f000 08:01 9179830    /usr/lib/ld-2.15.so
46eba000-47065000 r-xp 00000000 08:01 9179839    /usr/lib/libc-2.15.so
47065000-47066000 ---p 001ab000 08:01 9179839    /usr/lib/libc-2.15.so
47066000-47068000 r--p 001ab000 08:01 9179839    /usr/lib/libc-2.15.so
47068000-47069000 rw-p 001ad000 08:01 9179839    /usr/lib/libc-2.15.so
47069000-4706c000 rw-p 00000000 00:00 0 
47582000-4759e000 r-xp 00000000 08:01 9180054    /usr/lib/libgcc_s-4.7.2-20120921.so.1
4759e000-4759f000 rw-p 0001b000 08:01 9180054    /usr/lib/libgcc_s-4.7.2-20120921.so.1
b7769000-b776a000 rw-p 00000000 00:00 0 
b7781000-b7783000 rw-p 00000000 00:00 0 
b7783000-b7784000 r-xp 00000000 00:00 0          [vdso]
bffb8000-bffd9000 rw-p 00000000 00:00 0          [stack]
中止 (コアダンプ)

コアダンプするので、ulimited -c unlimitedとかしてcoreファイルを
はけばgdbでバックトレースできるよ。

Mudflapを使う

gcc4から使える機能です。バッファーオーバーフロー検出ツールです。
メモリの割り当てとして、ヒープ領域、bss領域、stack領域などがあります。このツールでは、下記のようなケースが検出されました。

/* test.c */
static char onbss[128];
int main(void)
{
    char onstack[128] = {0};
    int dummy;
    dummy = onbss[128];
    dummy = onstack[128];
    return 0;
}

ビルド方法は下記になります。

gcc -g -fmudflap test.c -lmudflap

実行結果

*******
mudflap violation 1 (check/read): time=1354703106.661039 ptr=0x80c9c80 size=129
pc=0xb76153ff location=`testflap.c:8:18 (main)'
      /lib/libmudflap.so.0(__mf_check+0x3f) [0xb76153ff]
      ./a.out(main+0xa5) [0x8048835]
      /lib/libmudflap.so.0(__wrap_main+0x4b) [0xb7614b4b]
Nearby object 1: checked region begins 0B into and ends 1B after
mudflap object 0x901d1e8: name=`testflap.c:1:13 onbss'
bounds=[0x80c9c80,0x80c9cff] size=128 area=static check=3r/0w liveness=3
alloc time=1354703106.660965 pc=0xb7614adf
number of nearby objects: 1
*******
mudflap violation 2 (check/read): time=1354703106.661411 ptr=0xbf85846c size=129
pc=0xb76153ff location=`testflap.c:9:20 (main)'
      /lib/libmudflap.so.0(__mf_check+0x3f) [0xb76153ff]
      ./a.out(main+0x11a) [0x80488aa]
      /lib/libmudflap.so.0(__wrap_main+0x4b) [0xb7614b4b]
Nearby object 1: checked region begins 0B into and ends 1B after
mudflap object 0x901e790: name=`testflap.c:5:10 (main) onstack'
bounds=[0xbf85846c,0xbf8584eb] size=128 area=stack check=3r/0w liveness=3
alloc time=1354703106.661027 pc=0xb7614adf
number of nearby objects: 1

一応、対応するソースコードの場所が表示されますが読みにくいです。valgrindの方が見やすいですね。ただvalgrindでは、bss領域、stack領域のオーバーフローは検出できないので、その点はすごい。

参考文献
Binary Hacks――ハッカー秘伝のテクニック100選

grub2からエントリーを削除

Linuxカーネルソースをビルドしてインストールした場合、

package-cleanup --oldkernels --count=1

では削除されない。※これで削除した場合は、エントリーも削除される。

起動時には、grub2がエントリーを表示してくれるが、それを手動で削除しないといけない。

/boot/grub2/grub.cfgを直接編集した。Fedora(3.6.7)エントリを削除するには、下記のような部分を削除する。

menuentry 'Fedora (3.6.7)' --class fedora --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-1d859624-ca03-411b-b92d-4cf74d5c6be2' {
        load_video
        set gfxpayload=keep
        insmod gzio
        insmod part_msdos
        insmod ext2
        set root='hd0,msdos1'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1'  1d859624-ca03-411b-b92d-4cf74d5c6be2
        else
          search --no-floppy --fs-uuid --set=root 1d859624-ca03-411b-b92d-4cf74d5c6be2
        fi
        echo 'Loading Fedora (3.6.7)'
        linux   /boot/vmlinuz-3.6.7 root=UUID=1d859624-ca03-411b-b92d-4cf74d5c6be2 ro rd.md=0 rd.lvm=0 rd.dm=0 SYSFONT=False rd.luks=0 LANG=ja_JP.UTF-8  KEYTABLE=jp106 rhgb quiet
        echo 'Loading initial ramdisk ...'
        initrd /boot/initramfs-3.6.7.img
}

kernelソースの取得

久しぶりの更新です。linuxカーネルのソース取得に関してです。
家では、Fedora17を利用しています。現在デバイスドライバソースコードを書いたりしていますが、fedora用にカスタマイズされたソースコードの取得方法をメモって置きます。

ソースの取得

yumdownloader --source kernel

SRPMファイルのインストール

rpm -ivh kernel-x.x.x-src.rpm

ソースの展開・パッチあて

cd ~/rpmbuild/SPEC
rpmbuild -bp kernel.spec

ふつうのLinuxプログラミング

最近、仕事でLinuxで開発しています。昔買った本を引っ張り出して読み直しています。
結構内容が詰まっていていいな。この本。

リバースエンジニアリング ―Pythonによるバイナリ解析技法

前、本屋でみて気になっていたので、買いました。

リバースエンジニアリング ―Pythonによるバイナリ解析技法 (Art Of Reversing)

リバースエンジニアリング ―Pythonによるバイナリ解析技法 (Art Of Reversing)