Page 1 of 1

partimaged problem with NPTL glibcdi

Posted: Tue Dec 26, 2006 2:45 pm
by thermal

I recently discovered a serious bug in partimaged which prevents it from working under recent distros with NPTL glibc (ie. Gentoo). The bug has already been described here but it seems to be yet unresolved.
The problem as written in the post above is indeed caused by differences in thread implementation between LinuxThreads and POSIX-compatible NPTL. On LinuxThreads when a new thread starts it`s given a new PID, UID and EUID. It`s essentially a different process. On the other hand with NPTL all threads share the same UID and EUID.
The partimaged server calls g_privs->ForceUser() when entering the thread function (partimaged() in src/server/partimaged.cpp). On LinuxThreads this works fine, the thread switches to an unpriviledged user and saves/restores the image. The main thread still runs with UID == 0 and can authenticate further clients. Unfortunately on NPTL when the thread switches UID and EUID to an unpriviledged user the main thread cannot authenticate clients anymore (partimag has no access to /etc/shadow). My quick solution is to simply replace the pthread_create with a fork() call for each connection. The provided patch does just that. Hope you include it as it may solve this problem for many people. For info about this topis visit:

-- >8

--- partimage/trunk/partimage/src/server/partimaged-main.cpp 2006-12-26 13:01:29.000000000 +0100
+++ partimage-new/trunk/partimage/src/server/partimaged-main.cpp 2006-12-26 13:44:12.000000000 +0100
@@ -32,6 +32,8 @@
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
+#include <errno.h>
+#include <cstring>

#include "net.h"
#include "netserver.h"
@@ -325,6 +327,7 @@
signal(SIGTERM, catch_sigint);
signal(SIGINT, catch_sigint);
signal(SIGSEGV, catch_sigint); // segmentation fault
+ signal(SIGCHLD, SIG_IGN); // ignore child exits
// signal(SIGHUP, catch_sigint);
// signal(SIGQUIT, catch_sigint);
// signal(SIGCHLD, catch_sigint);
@@ -433,10 +436,16 @@
g_Window->SetState(client, "error !");
g_Window->SetLocation(client, "(wrong password)");
- else
- pthread_create(&threads[client], NULL,
- partimaged, &client);
+ else
+ {
+ int rv = fork();
+ if ( rv < 0 )
+ {
+ showDebug(1, "Cannot fork() on incoming connection - %s\n", strerror(errno));
+ continue;
+ }
+ if ( ! rv ) partimaged(&client); // child process
+ }
} // internal loop

showDebug(1, "end of partimaged-main\n");