CVE:CVE-2009-2620
CNNVD:CNNVD-200907-417
Firebird是一款提供多个ANSI SQL-92功能的关系型数据库，可运行在Linux、Windows和各种Unix平台下 。
在Firebird的src/remote/server.cpp文件中，process_packet2()函数负责处理从客户端发送过来的报文。这个函数有一个switch语句考虑协议中所定义的所有可能的opcode 。
/-----------
src/remote/server.cpp:
...
3404P_OP op = receive->p_operation;
3405switch (op)
3406{
3407case op_connect:
...
3426case op_compile:
...
3430case op_attach:
...
- -----------/
在op_connect_request报文的情况下，执行流进入switch语句的以下case：
/-----------
src/remote/server.cpp:
...
3584case op_connect_request:
3585aux_request(port， &receive->p_req， sendL);
3586break;
- -----------/
在调用aux_request()函数并执行break语句后，执行流到达：
/-----------
src/remote/server.cpp:
...
3652if (port && port->port_state == state_broken) {
3653if (!port->port_parent) {
3654gds__log("SERVER/process_packet: broken port， server exiting");
3655port->disconnect(sendL， receive);
3656ThreadData::restoreSpecific();
3657return false;
3658}
3659port->disconnect(sendL， receive);
3660port = NULL;
3661}
- -----------/
通过在接收到op_connect_request报文时调试fbserver.exe二进制程序可以看出满足了第一个if语句的条件，但没有满足第二个if的条件，因此执行流到达port->disconnect()调用：
/-----------
005ACE2C|>837E 0C 03 CMP DWORD PTR DS:[ESI+C]，3
;port->port_state == state_broken ?
005ACE30|.75 1BJNZ SHORT fbserver.005ACE4D
005ACE32|.837E 1C 00 CMP DWORD PTR DS:[ESI+1C]，0
;port->port_parent == 0?
005ACE36|.75 0AJNZ SHORT fbserver.005ACE42
;this conditional jump is taken
005ACE38|.68 D4D65F00PUSH fbserver.005FD6D4
;ASCII "SERVER/process_packet: broken port， server exiting"
005ACE3D|.^ E9 44FDFFFFJMP fbserver.005ACB86
005ACE42|>53 PUSH EBX
; /Arg2
005ACE43|.57 PUSH EDI
; |Arg1
005ACE44|.8BCE MOV ECX，ESI
; |
005ACE46|.E8 65D7FFFFCALL <fbserver.rem_port::disconnect>
; \port->disconnect(sendL， receive)
- -----------/
根据src/remote/remote.h中的定义，port的类型为struct rem_port。这种结构类型在src/remote/server.cpp中实现了disconnect()函数：
/-----------
src/remote/server.cpp:
1464void rem_port::disconnect(PACKET* sendL， PACKET* receiveL)
- -----------/
在这个函数中执行以下代码以释放发送和接收的报文并关闭相关的套接字：
/-----------
src/remote/server.cpp:
...
1492REMOTE_free_packet(this， sendL);
1493REMOTE_free_packet(this， receiveL);
1494this->disconnect();
- -----------/
对this->disconnect()的调用最终会导致src/remote/inet.cpp中的disconnect()函数，该函数用于中断远程连接并接收rem_port结构参数。
/-----------
src/remote/inet.cpp:
1731static void disconnect( rem_port* port)
1732{
- -----------/
首先函数通过调用shutdown函数关闭客户端所创建的连接：
/-----------
src/remote/inet.cpp:
...
1763if (port->port_handle && (SOCKET) port->port_handle !=
INVALID_SOCKET) {
1764shutdown((int) port->port_handle， 2);
1765}
- -----------/
之后如果当前正在断开的rem_port结构是其他rem_port结构的子代，就会递归的调用disconnect()断开存储在port->port_async的rem_port。port_async是rem_port结构的成员，描述异步同级端口。
/-----------
src/remote/inet.cpp:
/* If this is a sub-port， unlink it from it's parent */
...
1789rem_port* parent = port->port_parent;
1790if (parent != NULL) {
1791if (port->port_async) {
1792disconnect(port->port_async);
1793port->port_async = NULL;
1794}
- -----------/
在执行对disconnect()的递归调用时，作为将要断开参数传送的port->port_async对应到主服务器套接字，也就是在3050/TCP端口上监听入站连接的套接字。一旦在递归调用中调用了shutdown()和closesocket()函数，服务器就会停止监听默认的3050/TCP端口，拒绝对合法用户的服务。
solution:Upgrade firebirdsql firebird to a higher version than 2.0.3,1.5,1.5.1,1.5.2,1.5.2.4731,1.5.3.4870,1.5.4.4910,1.5.5,2.0.0,2.0.0.12748,2.0.1,2.0.2,2.1,2.1.2,2.1.3:rc1,2.5,2.5:beta_2,and avoid the version (,2.0.3],1.5,1.5.1,1.5.2,1.5.2.4731,1.5.3.4870,1.5.4.4910,1.5.5,2.0.0,2.0.0.12748,2.0.1,2.0.2,2.1,2.1.2,2.1.3:rc1,2.5,2.5:beta_2