[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    OOM-killer prevention for master kdeinit process
From:       Lubos Lunak <l.lunak () suse ! cz>
Date:       2006-08-02 13:09:43
Message-ID: 200608021509.43918.l.lunak () suse ! cz
[Download RAW message or body]

Hello,

 short summary: Out Of Memory handling on Linux sucks, KDE can suffer badly 
from it, kernel devels are unable to do anything about it, so let's again 
work around things ourselves.

 Reading for this is 
http://www.lugroma.org/contenuti/eventi/LinuxDay2005/atti/Arcangeli-MemoryManagementKernel26.pdf . 
Only pages 8-11 are relevant, pages after that are unrelated, pages before 
that are either not really interesting or not true as long as KDE is 
concerned - somehow I get the impression that OOM-handling is worse and worse 
as the time goes (ah, and yes, I really hate it, just in case that's not 
obvious). Anyway, to the point:

 Run this:

ls /proc/*/oom_score | grep -v self | sed 's/\(.*\)\/\(.*\)/echo -n "\1 "; 
echo -n "`cat \1\/\2 2>\/dev\/null` "; readlink \1\/exe || echo/'| sh | 
sort -nr +1

That gives lines with </proc/pid> <likelyhood to be oom-killed> <binary>. 
Run "pstree -p" and compare it with the top of the list. The very first item 
that's going to be killed when running out of memory is going to be the 
master kdeinit process, i.e. the tiny thingy that is linked against our basic 
libraries which we use for launching apps. The reason why it's going to be 
killed the first is that OOM-killing has some "smart" heuristic that counts 
also all child processes into parent's score (it's mentioned in the paper) 
and since this process launches almost all KDE processes it gets the sum of 
almost whole KDE. No wonder it almost always wins the first place in the 
list. In fact, since the killing first kills all children of the "offending" 
process, that means that before memory is reclaimed to get out of OOM, 
various processes like klauncher or kwin are killed -> KDE is pretty 
unusable.

 We've already tried to make kernel developers turn that off, change it in 
order not to cause this kdeinit problem or at least give a better way to 
exclude kdeinit than to echo as root to somewhere in /proc, to no avail 
(because a good OOM-killer is apparently nothing trivial and also because 
kernel developers have funny ideas about userspace). So we somewhere need to 
do something like "echo -10 > /proc/<pid_of_kdeinit>/oom_adjust" as root when 
running on Linux ( -10 means the score will be multiplied by 2^-10, i.e. 
divided by 1024 ; given that kdeinit is very unlikely to go haywire that 
seems pretty safe).

 Now, who's the setuid guru here :)? Is the attached (KDE3) patch ok? I'd 
prefer not to have security people going after me. The setuid stuff is copied 
from artswrapper, the privileges are dropped immediately so I hope there's no 
problem.


PS: Just in case somebody wonders why I hate OOM handling on Linux so much 
then the answer is that my 1G RAM work machine with no swap at all being 
trashed to death is probably the top reason why I reboot it (not that I 
reboot that often otherwise).

-- 
Lubos Lunak
KDE developer
---------------------------------------------------------------------
SuSE CR, s.r.o.  e-mail: l.lunak@suse.cz , l.lunak@kde.org
Drahobejlova 27  tel: +420 2 9654 2373
190 00 Praha 9   fax: +420 2 9654 2374
Czech Republic   http://www.suse.cz/

["kinit.patch" (text/x-diff)]

--- kinit/kinit.cpp.sav	2006-05-24 18:34:48.000000000 +0200
+++ kinit/kinit.cpp	2006-08-02 15:07:33.000000000 +0200
@@ -1654,6 +1654,27 @@ int main(int argc, char **argv, char **e
    int keep_running = 1;
    int new_startup = 0;
    d.suicide = false;
+   
+#ifdef __linux__
+/* prevent getting killed by bad heuristic in Linux OOM-killer and drop root \
privileges */ +   FILE* procfile = fopen( "/proc/self/oom_adj", "w" );
+   if( procfile ) {
+      fprintf( procfile, "-10" );
+      fclose( procfile );
+   }
+   if (geteuid() != getuid()) 
+   {
+#if defined (HAVE_SETEUID) && !defined (HAVE_SETEUID_FAKE) 
+      seteuid(getuid());
+#else
+      setreuid(-1, getuid());
+#endif
+      if (geteuid() != getuid()) {
+         perror("setuid()");
+         exit(1);
+      }
+   }
+#endif   
 
    /** Save arguments first... **/
    char **safe_argv = (char **) malloc( sizeof(char *) * argc);
--- kinit/Makefile.am.sav	2005-09-29 21:31:28.000000000 +0200
+++ kinit/Makefile.am	2006-08-02 14:58:11.000000000 +0200
@@ -77,6 +77,14 @@ shell.o: wrapper.c
 dummy.cpp:
 	echo > dummy.cpp
 
+if KDEINIT_SETUID
+# kdeinit needs to be installed setuid root on Linux
+install-exec-hook:
+	@(chown 0 $(DESTDIR)$(bindir)/kdeinit && chmod 4755 $(DESTDIR)$(bindir)/kdeinit) || \
echo "Please make kdeinit setuid root" >&2 +	@echo ""
+	@echo "kdeinit is by default installed on Linux with a set SETUID root bit!"
+	@echo "This is needed to prevent it from being killed by a bad heuristic in the \
OOM-killer when running out of memory." +	@echo ""
+endif
 
 include $(top_srcdir)/admin/Doxyfile.am
-
--- kinit/configure.in.in.sav	2005-05-04 12:52:23.000000000 +0200
+++ kinit/configure.in.in	2006-08-02 14:57:00.000000000 +0200
@@ -43,3 +43,15 @@ if test -n "$KDEINIT_FONTCONFIG"; then
     AC_DEFINE(KDEINIT_USE_FONTCONFIG,1,[Use FontConfig in kdeinit])
 fi
 AC_SUBST(KDEINIT_XFT_INCLUDES)
+
+AC_MSG_CHECKING(whether to make kdeinit setuid root in order to protect it from bad \
Linux OOM-killer) +kdeinit_setuid=
+case $target_os in
+    linux*)
+        AC_MSG_RESULT(yes)
+        kdeinit_setuid=1
+        ;;
+    *)  AC_MSG_RESULT(no)
+        ;;
+esac
+AM_CONDITIONAL(KDEINIT_SETUID, test -n "$kdeinit_setuid" )



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic