Wednesday, March 11, 2009

g_thread_init

This afternoon I spent almost two hours hunting a memory leak reported by valgrind. It said that there are 2034 bytes definitely lost in g_hash_table_new_full(), but I am pretty sure that g_hash_table_destroy() is invoked with each key been passed to g_free().

The fix turned out to be a slight modification of call sequence to g_thread_init(), from:
  1. create hash table
  2. add hash entry
  3. g_thread_init()
  4. reclaim hash table
to:
  1. g_thread_init()
  2. create hash table
  3. add hash entry
  4. reclaim hash table
then, the error memory leak error just vanished.

Labels: ,

Monday, February 23, 2009

debug-set!

If you wrote a scheme procedure which will recursive too much and exhaust all you stack, guile will print a horrible error message like below:
ERROR: Stack overflow
You might fix your algorithm and make the procedure tail-recursive to get rid of the compliant, or either, for debugging purpose, increase the stack size:
(debug-set! stack 200000)

Labels: ,

Wednesday, February 18, 2009

reconnect

Several days ago there was a bug reported that our XML-RPC client over SSL will compliant that "no data is available" when trying to read the HTTP header from the server. Since it is a P2-critical bug, I spent a lot of time debugging it immediately.

GDB shows me that "BIO_read()" returned zero when reading the HTTP header, and its manual said that:
A 0 or -1 return is not necessarily an indication of an error. In par-
ticular when the source/sink is non-blocking or of a certain type it
may merely be an indication that no data is currently available and
that the application should retry the operation later.

But finally I can see that when we switching to HTTP from HTTPS, the client works just fine. And later, we are confirmed that the SSL handling in the server side has a race condition and the connection would be shutdown by then.

In order to make the client more robust, I worked our a patch to do reconnection. The result is rather exciting -- I did thousands of XML-RPC calls over a persistent connection, and everything works perfectly.

At last, I am glad to share that, in section 6.3 of "UNIX Network Programming Volume 1", the author described the conditions that a descriptor being select() is ready for read:

b. The read half of the connection is closed (i.e., a TCP connection that has received a FIN). A read operation on the socket will not block and will return 0 (i.e., EOF).

Actually our underlying socket is handled by select() , and I checked that BIO_get_close() really returns 1 when the connection is closed by the server.

Labels: ,

Monday, December 08, 2008

autoconf

I submitted another patch to libxr mailing list just now, it is used to fix the small bug in `configure.ac', so that libxr will generate a correct `xr-config.h' when a JSON run-time is found.

I started to contribute to libxr since last Dec., and I consider it my first real participation in OSS development. Yes I've previous experiences writting test suites for openhpi, openipmi and openwsman, during my internship. But frankly speaking, I had few feelings of joy then.

I enjoyed the discussion in E-mail, and I'd like to thank the author of libxr, who gave me a lot of helps.

Labels:

Thursday, December 04, 2008

timeout

Eventually I managed to add a timeout value in the server side code so that an idle connection will be shutdown [patch] within a given time. The patch is much simpler than what's expected, and at the same time, I realized that I did NOT turn libxr back to non-blocking I/O, but non-buffering I/O.

I solved another problem which blocked our development this afternoon. It turned out to be SSL re-handshake problem -- as I guessed. Adding a Squid proxy between our client and server application is not that transparent as we thought, it will request the server program to do SSL re-handshake.

Labels: ,

Wednesday, December 03, 2008

First git branch

I just created my first git branch of libxr with the command line:
# git checkout -b non-blocking
# git commit -a

Of course, the first commit is a patch which turns libxr back to non-blocking I/O. The next step is to setup the time out value of waiting incoming HTTP header.

BTW, I am also planning to spare sometime writing a document about libxr, with XeTeX.

Labels: ,

Tuesday, December 02, 2008

P1 bug

These days I've been occupied by a P1 bug and, unfortunately, the fix is far from ready.

The XML-RPC library we use has a thread pool with each thread serves incoming request, and the thread will not be ripped back to the pool until the client shuts down the connection. The problem is, when the number of established connection prevails the number of worker threads, the following connection will be blocked.

Since the library uses buffered I/O thus blocking, the first step I need to take is to change it back to non-blocking I/O style -- If a connection has been idle for a while, we might have a chance to shut it down.

My brain now is jammed with confusion and I felt quit dizzy, as many newbies who are trying openssl programming. Just too many stuff!
  1. buffered I/O
  2. chained BIO
  3. blocking I/O
  4. non-blocking I/O
  5. BIO with select()

Labels: ,

Tuesday, June 03, 2008

code injection

有很多文章关于代码注入,主要过程是用ptrace系统调用attach一个进程,注入代码(shellcode),然后再detach该进程使得被注入 的代码得以执行。通常注入的代码被存放于堆栈中,因为它的大小可以动态调整,并且这些``蛛丝马迹''执行后可以被后续过程调用擦除。然而现代CPU(如 Intel IA32)都包含了NX位,即可修改内存不可执行(writable xor executable),这使得大部分注入到stack中的shellcode都无法运行,从而提高了系统的安全性。

有许多方法可以绕过该限制,比如: return to libc。作为代码注入的示例,我们可以直接将代码注入到EIP指向的内存区域:
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
perror("ptrace failed");
exit(-1);
}

waitpid(pid, NULL, 0);
printf("[1] - Process attached\n");

if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)!=-1) {
printf("[2] - Extract register eip (0x%.8x)\n", regs.eip);

for (i=0; i ptrace(PTRACE_POKEDATA, pid, regs.eip+i, *(int*)(injected_code+i));
printf("[3] - Code inserted\n");
}

ptrace(PTRACE_DETACH, pid, NULL, NULL);
printf("[4] - Running Code\n");
其 中injected_code即为shellcode首地址,一般以汇编语言书写,如上例as风格汇编代码(当然一般是exece("/bin/sh", ["/bin/sh", NULL], NULL)。由于被注入进程的文本段被修改,这样该进程的行为被修改,这并不是一个好主意。这里仅仅是代码注入的一个简单示例罢了。

INJECTED_LEN是被注入代码的字节长度,可以由size命令获得。

Labels: , ,

汇编语言的艺术

Linux下使用汇编语言 有很多选择:内联汇编,as或者nasm/yasm,下面是使用 as的例子:
.text
.globl _start
_start:
jmp get_string
print_string:
movl $4, %eax /* __NR_write */
movl $1, %ebx
popl %ecx
movl $6, %edx
int $0x80

movl %eax, %ebx
movl $1, %eax /* __NR_exit */
int $0x80

get_string:
call print_string
.string "hello\n"

这 段汇编使用了传统的int $0x80系统调用,这里最重要的窍门是怎样获取字符串的首地址(call/popl)。这个小技巧使得生成的代码是位置无关的(PIC - Position Independent Code)。这在code injection中注入shellcode非常普遍。

Labels: , ,