Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Evergreen:11.2
kdelibs4
oom-protect.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File oom-protect.diff of Package kdelibs4
Index: kinit/start_kdeinit.c =================================================================== --- kinit/start_kdeinit.c (revision 0) +++ kinit/start_kdeinit.c (revision 1001887) @@ -0,0 +1,176 @@ +/* + * This file is part of the KDE libraries + * Copyright (c) 2006 Lubos Lunak <l.lunak@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <config.h> +#include <config-prefix.h> +#include <config-kdeinit.h> + +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define EXECUTE BIN_INSTALL_DIR "/kdeinit4" + +#ifdef KDEINIT_OOM_PROTECT + +/* + Prevent getting killed by bad heuristic in Linux OOM-killer. + This wrapper decreases the chance OOM killer kills it (or its children, + namely kdeinit), opens a pipe and forks. Child drops privileges + and launches kdeinit. Since processes started by kdeinit should + not have this protection, kdeinit will after forking send the new + PID using the pipe and wait for a signal. This parent will reset the protection + and SIGUSR1 the process to continue. + returns 1 if pid is valid +*/ + +static int set_protection( pid_t pid, int enable ) +{ + char buf[ 1024 ]; + int procfile; + sprintf( buf, "/proc/%d/stat", pid ); + if( !enable ) { + /* Be paranoid and check that the pid we got from the pipe + belongs to this user. */ + struct stat st; + if( lstat( buf, &st ) < 0 || st.st_uid != getuid()) + return 0; + } + sprintf( buf, "/proc/%d/oom_adj", pid ); + procfile = open( buf, O_WRONLY ); + if( procfile >= 0 ) { + if( enable ) + write( procfile, "-5", sizeof( "-5" )); + else + write( procfile, "0", sizeof( "0" )); + close( procfile ); + } + return 1; +} + +int main(int argc, char **argv) +{ + int pipes[ 2 ]; + int new_argc; + const char** new_argv; + char helper_num[ 1024 ]; + unsigned i; + char** orig_environ = NULL; + char header[ 7 ]; + if( pipe( pipes ) < 0 ) { + perror( "pipe()" ); + return 1; + } + if( argc < 0 || argc > 1000 ) + abort(); /* paranoid */ + set_protection( getpid(), 1 ); + switch( fork()) { + case -1: + perror( "fork()" ); + return 1; + default: /* parent, drop privileges and exec */ + if (setgid(getgid())) { + perror("setgid()"); + return 1; + } + if (setuid(getuid()) || geteuid() != getuid()) { + perror("setuid()"); + return 1; + } + close( pipes[ 0 ] ); + /* read original environment passed by start_kdeinit_wrapper */ + if( read( 0, header, 7 ) == 7 && strncmp( header, "environ", 7 ) == 0 ) { + unsigned count; + if( read( 0, &count, sizeof( unsigned )) == sizeof( unsigned ) + && count && count < (1<<16)) { + char** env = malloc(( count + 1 ) * sizeof( char* )); + int ok = 1; + for( i = 0; + i < count && ok; + ++i ) { + unsigned len; + if( read( 0, &len, sizeof( unsigned )) == sizeof( unsigned ) + && len && len < (1<<12)) { + env[ i ] = malloc( len + 1 ); + if( (unsigned) read( 0, env[ i ], len ) == len ) { + env[ i ][ len ] = '\0'; + } else { + ok = 0; + } + } + } + if( ok ) { + env[ i ] = NULL; + orig_environ = env; + } + } + } + if(argc == 0) + return 1; + new_argc = argc + 2; + new_argv = malloc( sizeof( char* ) * ( new_argc + 1 )); + if( new_argv == NULL ) + return 1; + new_argv[ 0 ] = EXECUTE; + new_argv[ 1 ] = "--oom-pipe"; + sprintf( helper_num, "%d", pipes[ 1 ] ); + new_argv[ 2 ] = helper_num; + for( i = 1; + i <= (unsigned) argc; + ++i ) + new_argv[ i + 2 ] = argv[ i ]; + if( orig_environ ) + execve(EXECUTE, (char**)new_argv, orig_environ); + else + execv(EXECUTE, (char**)new_argv); + perror(EXECUTE); + return 1; + case 0: /* child, keep privileges and do the privileged work */ + close( pipes[ 1 ] ); + for(;;) { + pid_t pid = 0; + int ret = read( pipes[ 0 ], &pid, sizeof( pid_t )); + if( ret < 0 && errno == EINTR ) + continue; + if( ret <= 0 ) /* pipe closed or error, exit */ + _exit(0); + if( pid != 0 ) { + if (set_protection( pid, 0 )) + kill( pid, SIGUSR1 ); + } + } + } +} + +#else /* not Linux, the simple non-setuid case */ + +int main(int argc, char **argv) +{ + if(argc == 0) + return 1; + argv[0] = (char*)EXECUTE; + execv(EXECUTE,argv); + perror(EXECUTE); + return 1; +} +#endif Index: kinit/start_kdeinit_wrapper.c =================================================================== --- kinit/start_kdeinit_wrapper.c (revision 0) +++ kinit/start_kdeinit_wrapper.c (revision 1001887) @@ -0,0 +1,96 @@ +/* + * This file is part of the KDE libraries + * Copyright (c) 2007 Lubos Lunak <l.lunak@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <config.h> +#include <config-prefix.h> +#include <config-kdeinit.h> + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#define EXECUTE LIBEXEC_INSTALL_DIR "/start_kdeinit" + +#ifdef KDEINIT_OOM_PROTECT + +/* + The start_kdeinit wrapper is setuid, which means some shell variables like LD_LIBRARY_PATH + get unset before it's launched. However kdeinit is used to launch most of KDE, so such variables + should not be dropped. Therefore this wrapper for the setuid wrapper read the environment + and writes it to start_kdeinit's stdin, which after dropping priviledges reads it and uses it + for launching the real kdeinit. +*/ +int main(int argc, char **argv) +{ + int pipes[ 2 ]; + if(argc == 0) + return 1; + if( pipe( pipes ) < 0 ) { + perror( "pipe()" ); + return 1; + } + switch( fork()) { + case -1: + perror( "fork()" ); + return 1; + default: /* parent, exec */ + close( pipes[ 1 ] ); + close( 0 ); /* stdin */ + dup2( pipes[ 0 ], 0 ); + close( pipes[ 0 ] ); + argv[ 0 ] = (char*)EXECUTE; + execvp(EXECUTE, argv); + perror("start_kdeinit"); + return 1; + case 0: { /* child, pass env and exit */ + extern char** environ; + int i; + close( pipes[ 0 ] ); + write( pipes[ 1 ], "environ", 7 ); /* header, just in case */ + for( i = 0; + environ[ i ] != NULL; + ++i ) + {} + write( pipes[ 1 ], &i, sizeof( int )); /* write count */ + for( i = 0; + environ[ i ] != NULL; + ++i ) + { + int len = strlen( environ[ i ] ); + write( pipes[ 1 ], &len, sizeof( int )); /* write length */ + write( pipes[ 1 ], environ[ i ], strlen( environ[ i ] )); + } + close( pipes[ 1 ] ); + } + } + return 0; +} + +#else /* not Linux, the simple non-setuid case */ + +int main(int argc, char **argv) +{ + if(argc == 0) + return 1; + argv[0] = (char*)EXECUTE; + execvp(EXECUTE,argv); + perror("start_kdeinit"); + return 1; +} +#endif Index: kinit/proctitle.cpp =================================================================== --- kinit/proctitle.cpp (revision 1000152) +++ kinit/proctitle.cpp (revision 1001887) @@ -80,6 +80,7 @@ #if PF_ARGV_TYPE == PF_ARGV_WRITEABLE /* Only this mode uses LastArgv */ static char *LastArgv = NULL; +static char *cleanUpTo = NULL; #endif /** @@ -114,6 +115,7 @@ LastArgv = argv[i] + strlen(argv[i]); } } + cleanUpTo = LastArgv; for (i = 0; envp[i] != NULL; i++) { /* must not overwrite XDG_SESSION_COOKIE */ @@ -201,17 +203,15 @@ /* We can overwrite individual argv[] arguments. Semi-nice. */ snprintf(Argv[0], maxlen, "%s", statbuf); p = &Argv[0][i]; - - /* null terminate it, but don't clear the rest of the - memory that is usually used for environment variables. Some + /* Clear the rest used by arguments, but don't clear the memory + that is usually used for environment variables. Some tools, like ConsoleKit must have access to the process'es initial environment (more exact, the XDG_SESSION_COOKIE variable stored there). If this code causes another side effect, we have to specifically always append those variables to our environment. */ + while (p < cleanUpTo) + *p++ = '\0'; - if (p < LastArgv) - *p = '\0'; - Argv[1] = NULL; # endif /* PF_ARGV_WRITEABLE */ Index: kinit/kinit.cpp =================================================================== --- kinit/kinit.cpp (revision 1000152) +++ kinit/kinit.cpp (revision 1001887) @@ -22,6 +22,7 @@ #define QT_NO_CAST_FROM_ASCII #include <config.h> +#include <config-kdeinit.h> #include <sys/types.h> #include <sys/time.h> @@ -34,6 +35,7 @@ #include <sys/select.h> // Needed on some systems. #endif +#include <ctype.h> #include <errno.h> #include <fcntl.h> #include "proctitle.h" @@ -84,12 +86,6 @@ #include <kstartupinfo.h> #endif -#if KDE_IS_VERSION( 3, 90, 0 ) -#ifdef __GNUC__ -#warning Check if Linux OOM-killer still sucks and if yes, forwardport revision 579164 and following fixes. -#endif -#endif - // #define SKIP_PROCTITLE 1 extern char **environ; @@ -421,6 +417,38 @@ return QFile::encodeName(execpath); } +#ifdef KDEINIT_OOM_PROTECT +static int oom_pipe = -1; + +static void oom_protect_sighandler( int ) { +} + +static void reset_oom_protect() { + if( oom_pipe <= 0 ) + return; + struct sigaction act, oldact; + act.sa_handler = oom_protect_sighandler; + act.sa_flags = 0; + sigemptyset( &act.sa_mask ); + sigaction( SIGUSR1, &act, &oldact ); + sigset_t sigs, oldsigs; + sigemptyset( &sigs ); + sigaddset( &sigs, SIGUSR1 ); + sigprocmask( SIG_BLOCK, &sigs, &oldsigs ); + pid_t pid = getpid(); + if( write( oom_pipe, &pid, sizeof( pid_t )) > 0 ) { + sigsuspend( &oldsigs ); // wait for the signal to come + } + sigprocmask( SIG_SETMASK, &oldsigs, NULL ); + sigaction( SIGUSR1, &oldact, NULL ); + close( oom_pipe ); + oom_pipe = -1; +} +#else +static void reset_oom_protect() { +} +#endif + static pid_t launch(int argc, const char *_name, const char *args, const char *cwd=0, int envc=0, const char *envs=0, bool reset_env = false, @@ -505,6 +533,7 @@ /** Child **/ close(d.fd[0]); close_fds(); + reset_oom_protect(); // Try to chdir, either to the requested directory or to the user's document path by default. // We ignore errors - if you write a desktop file with Exec=foo and Path=/doesnotexist, @@ -1601,6 +1630,10 @@ printf("KDE: %s\n", KDE_VERSION_STRING); exit(0); } +#ifdef KDEINIT_OOM_PROTECT + if (strcmp(safe_argv[i], "--oom-pipe") == 0 && i+1<argc) + oom_pipe = atol(argv[i+1]); +#endif if (strcmp(safe_argv[i], "--help") == 0) { printf("Usage: kdeinit4 [options]\n"); @@ -1750,7 +1783,11 @@ #endif handle_requests(pid); } - else if (safe_argv[i][0] == '-') + else if (safe_argv[i][0] == '-' +#ifdef KDEINIT_OOM_PROTECT + || isdigit(safe_argv[i][0]) +#endif + ) { // Ignore } Index: kinit/config-kdeinit.h.cmake =================================================================== --- kinit/config-kdeinit.h.cmake (revision 1000152) +++ kinit/config-kdeinit.h.cmake (revision 1001887) @@ -1,8 +1,10 @@ -// These are for proctitle.cpp: +/* These are for proctitle.cpp: */ #cmakedefine HAVE___PROGNAME 1 #cmakedefine HAVE___PROGNAME_FULL 1 #cmakedefine HAVE_SYS_PSTAT_H 1 #cmakedefine HAVE_PSTAT 1 #cmakedefine HAVE_SETPROCTITLE 1 +/* for start_kdeinit */ +#cmakedefine KDEINIT_OOM_PROTECT 1 Index: kinit/CMakeLists.txt =================================================================== --- kinit/CMakeLists.txt (revision 1000152) +++ kinit/CMakeLists.txt (revision 1001887) @@ -17,8 +17,6 @@ check_include_files(unistd.h HAVE_UNISTD_H) check_function_exists(pstat HAVE_PSTAT) check_function_exists(setproctitle HAVE_SETPROCTITLE) -configure_file(config-kdeinit.h.cmake - ${CMAKE_CURRENT_BINARY_DIR}/config-kdeinit.h ) # used by 4 executables in this file @@ -149,7 +147,35 @@ target_link_libraries( klauncher kdeinit_klauncher ) install(TARGETS klauncher DESTINATION ${LIBEXEC_INSTALL_DIR} ) +########### start_kdeinit ############### +if (NOT WIN32) + set(start_kdeinit_SRCS start_kdeinit.c) + kde4_add_executable(start_kdeinit ${start_kdeinit_SRCS}) + if(KDE4_ENABLE_FPIE) + macro_add_compile_flags(start_kdeinit ${KDE4_CXX_FPIE_FLAGS}) + macro_add_link_flags(start_kdeinit ${KDE4_PIE_LDFLAGS}) + endif(KDE4_ENABLE_FPIE) + + set(start_kdeinit_wrapper_SRCS start_kdeinit_wrapper.c) + kde4_add_executable(start_kdeinit_wrapper ${start_kdeinit_wrapper_SRCS}) + + install(TARGETS start_kdeinit DESTINATION ${LIBEXEC_INSTALL_DIR}) + install(TARGETS start_kdeinit_wrapper DESTINATION ${LIBEXEC_INSTALL_DIR}) +endif (NOT WIN32) + +if (CMAKE_SYSTEM_NAME MATCHES Linux) + MESSAGE(STATUS "Using setuid root kdeinit wrapper in order to protect it from bad Linux OOM-killer") + set(KDEINIT_OOM_PROTECT 1) + install(CODE " + set(START_KDEINIT_PATH \"\$ENV{DESTDIR}${LIBEXEC_INSTALL_DIR}/start_kdeinit\") + EXECUTE_PROCESS(COMMAND sh -c \"chown root '\${START_KDEINIT_PATH}' && chmod u+s '\${START_KDEINIT_PATH}'\") + ") +endif (CMAKE_SYSTEM_NAME MATCHES Linux) + ########### install files ############### install( FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.KLauncher.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} ) +########### config-kdeinit.h ############ +configure_file(config-kdeinit.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/config-kdeinit.h )
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor