From kde-core-devel Wed Aug 02 13:09:43 2006 From: Lubos Lunak Date: Wed, 02 Aug 2006 13:09:43 +0000 To: kde-core-devel Subject: OOM-killer prevention for master kdeinit process Message-Id: <200608021509.43918.l.lunak () suse ! cz> X-MARC-Message: https://marc.info/?l=kde-core-devel&m=115452589706095 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--Boundary-00=_XQK0EfcGHA3FkN3" --Boundary-00=_XQK0EfcGHA3FkN3 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline 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 . 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//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/ --Boundary-00=_XQK0EfcGHA3FkN3 Content-Type: text/x-diff; charset="us-ascii"; name="kinit.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kinit.patch" --- 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" ) --Boundary-00=_XQK0EfcGHA3FkN3--