[PATCH] daemon: drop root privileges and use the helper
by Federico Simoncelli
This patch lets the daemon drop the root privileges and routes the kill
requests to the helper.
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
src/helper.c | 7 +++++-
src/helper.h | 4 ++-
src/main.c | 63 ++++++++++++++++++++++++++++++++++++++++++---------------
3 files changed, 55 insertions(+), 19 deletions(-)
diff --git a/src/helper.c b/src/helper.c
index 4084e87..4e3fb9a 100644
--- a/src/helper.c
+++ b/src/helper.c
@@ -192,7 +192,10 @@ int run_helper(int in_fd, int out_fd, int log_stderr)
if (pollfd.revents & POLLIN) {
rv = read_hm(in_fd, &hm);
- if (!rv && (hm.type == HELPER_MSG_RUNPATH)) {
+ if (rv)
+ continue;
+
+ if (hm.type == HELPER_MSG_RUNPATH) {
pid = fork();
if (!pid) {
run_path(&hm);
@@ -206,6 +209,8 @@ int run_helper(int in_fd, int out_fd, int log_stderr)
pid, fork_count, wait_count,
hm.path, hm.args);
*/
+ } else if (hm.type == HELPER_MSG_KILLPID) {
+ kill(hm.pid, hm.sig);
}
}
diff --git a/src/helper.h b/src/helper.h
index f55b051..b87bc61 100644
--- a/src/helper.h
+++ b/src/helper.h
@@ -18,6 +18,7 @@
#define SANLK_HELPER_MSG_LEN 512
#define HELPER_MSG_RUNPATH 1
+#define HELPER_MSG_KILLPID 2
struct helper_msg {
uint8_t type;
@@ -25,9 +26,10 @@ struct helper_msg {
uint16_t pad2;
uint32_t flags;
int pid;
+ int sig;
char path[SANLK_HELPER_PATH_LEN]; /* 128 */
char args[SANLK_HELPER_ARGS_LEN]; /* 128 */
- char pad[244];
+ char pad[240];
};
#define HELPER_STATUS_INTERVAL 30
diff --git a/src/main.c b/src/main.c
index 34d92f1..af39987 100644
--- a/src/main.c
+++ b/src/main.c
@@ -53,6 +53,8 @@
#define RELEASE_VERSION "2.3"
+#define SIGHELPER 100 /* anything that's not SIGTERM/SIGKILL */
+
struct thread_pool {
int num_workers;
int max_workers;
@@ -111,7 +113,7 @@ static void close_helper(void)
* msgs before getting EAGAIN.
*/
-static void send_helper_kill(struct client *cl)
+static void send_helper_kill(struct client *cl, int sig)
{
struct helper_msg hm;
int rv;
@@ -129,12 +131,17 @@ static void send_helper_kill(struct client *cl)
return;
memset(&hm, 0, sizeof(hm));
- hm.type = HELPER_MSG_RUNPATH;
- memcpy(hm.path, cl->killpath, SANLK_HELPER_PATH_LEN);
- memcpy(hm.args, cl->killargs, SANLK_HELPER_ARGS_LEN);
- if (cl->flags & CL_KILLPATH_PID)
- hm.pid = cl->pid;
+ if (sig == SIGHELPER) {
+ hm.type = HELPER_MSG_RUNPATH;
+ memcpy(hm.path, cl->killpath, SANLK_HELPER_PATH_LEN);
+ memcpy(hm.args, cl->killargs, SANLK_HELPER_ARGS_LEN);
+ } else {
+ hm.type = HELPER_MSG_KILLPID;
+ hm.sig = sig;
+ }
+
+ hm.pid = cl->pid;
retry:
rv = write(helper_kill_fd, &hm, sizeof(hm));
@@ -514,8 +521,6 @@ static int client_using_space(struct client *cl, struct space *sp)
return rv;
}
-#define SIG_HELPER 100 /* anything that's not SIGTERM/SIGKILL */
-
static void kill_pids(struct space *sp)
{
struct client *cl;
@@ -578,7 +583,7 @@ static void kill_pids(struct space *sp)
(helper_kill_fd != -1) &&
(cl->kill_count <= main_task.kill_count_term) &&
(now - helper_last_status < (HELPER_STATUS_INTERVAL * 2)))
- sig = SIG_HELPER;
+ sig = SIGHELPER;
else if (cl->restrict & SANLK_RESTRICT_SIGKILL)
sig = SIGTERM;
else if (cl->restrict & SANLK_RESTRICT_SIGTERM)
@@ -603,10 +608,7 @@ static void kill_pids(struct space *sp)
ci, fd, pid, sig, cl->kill_count);
}
- if (sig == SIG_HELPER)
- send_helper_kill(cl);
- else
- kill(pid, sig);
+ send_helper_kill(cl, sig);
}
}
@@ -1295,10 +1297,27 @@ static void setup_groups(void)
int rv, i, j, h;
int pngroups, sngroups, ngroups_max;
gid_t *pgroup, *sgroup;
+ struct rlimit rlim;
if (!com.uname || !com.gname)
return;
+ /* before switching to a different user/group we must configure
+ the limits form memlock and rtprio */
+ rlim.rlim_cur = rlim.rlim_max= -1;
+
+ rv = setrlimit(RLIMIT_MEMLOCK, &rlim);
+ if (rv < 0) {
+ log_error("cannot set the limits for memlock %i", errno);
+ exit(EXIT_FAILURE);
+ }
+
+ rv = setrlimit(RLIMIT_RTPRIO, &rlim);
+ if (rv < 0) {
+ log_error("cannot set the limits for rtprio %i", errno);
+ exit(EXIT_FAILURE);
+ }
+
ngroups_max = sysconf(_SC_NGROUPS_MAX);
if (ngroups_max < 0) {
log_error("cannot get the max number of groups %i", errno);
@@ -1352,6 +1371,16 @@ static void setup_groups(void)
goto out;
}
+ rv = setgid(com.gid);
+ if (rv < 0) {
+ log_error("cannot set group id to %i errno %i", com.gid, errno);
+ }
+
+ rv = setuid(com.uid);
+ if (rv < 0) {
+ log_error("cannot set user id to %i errno %i", com.uid, errno);
+ }
+
out:
free(pgroup);
}
@@ -1519,16 +1548,16 @@ static int do_daemon(void)
if (rv < 0)
return rv;
- fd = lockfile(SANLK_RUN_DIR, SANLK_LOCKFILE_NAME);
- if (fd < 0)
- return fd;
-
setup_logging();
setup_host_name();
setup_groups();
+ fd = lockfile(SANLK_RUN_DIR, SANLK_LOCKFILE_NAME);
+ if (fd < 0)
+ return fd;
+
log_error("sanlock daemon started %s aio %d %d renew %d %d host %s time %llu",
RELEASE_VERSION,
main_task.use_aio, main_task.io_timeout_seconds,
--
1.7.1
11 years, 9 months
[PATCH] python: add the support for killpath
by Federico Simoncelli
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
python/sanlock.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 84 insertions(+), 0 deletions(-)
diff --git a/python/sanlock.c b/python/sanlock.c
index d953c90..bef236e 100644
--- a/python/sanlock.c
+++ b/python/sanlock.c
@@ -537,6 +537,88 @@ exit_fail:
return NULL;
}
+/* killpath */
+PyDoc_STRVAR(pydoc_killpath, "\
+killpath(path, args [, slkfd=fd])\n\
+Configure the path and arguments of the executable used to fence a\n\
+process either by causing the pid to exit (kill) or putting it into\n\
+a safe state (resources released).\n\
+The arguments must be in the format: [\"arg1\", \"arg2\", ...]");
+
+static PyObject *
+py_killpath(PyObject *self __unused, PyObject *args, PyObject *keywds)
+{
+ int rv, i, j, n, num_args, sanlockfd = -1;
+ char *p, *path, kpargs[SANLK_HELPER_ARGS_LEN];
+ PyObject *argslist, *item;
+
+ static char *kwlist[] = {"path", "args", "slkfd", NULL};
+
+ /* parse python tuple */
+ if (!PyArg_ParseTupleAndKeywords(args, keywds, "sO!|i", kwlist,
+ &path, &PyList_Type, &argslist, &sanlockfd)) {
+ return NULL;
+ }
+
+ /* checking the path length */
+ if (strlen(path) + 1 > SANLK_HELPER_PATH_LEN) {
+ __set_exception(EINVAL, "Killpath path argument too long");
+ return NULL;
+ }
+
+ num_args = PyList_Size(argslist);
+ memset(kpargs, 0, SANLK_HELPER_ARGS_LEN);
+
+ /* creating the arguments string from a python list */
+ for (i = 0, n = 0; i < num_args; i++) {
+ size_t arg_len;
+
+ item = PyList_GetItem(argslist, i);
+ p = PyString_AsString(item);
+
+ if (p == NULL) {
+ __set_exception(EINVAL, "Killpath argument not a string");
+ return NULL;
+ }
+
+ /* computing the argument length considering the escape chars */
+ for (j = 0, arg_len = 0; p[j]; j++, arg_len++) {
+ if (p[j] == ' ' || p[j] == '\\') arg_len++;
+ }
+
+ /* adding 2 for the space separator ' ' and the '\0' terminator */
+ if (n + arg_len + 2 > SANLK_HELPER_ARGS_LEN) {
+ __set_exception(EINVAL, "Killpath arguments are too long");
+ return NULL;
+ }
+
+ /* adding the space separator between arguments */
+ if (n > 0) {
+ kpargs[n++] = ' ';
+ }
+
+ while (*p) {
+ if (*p == ' ' || *p == '\\') {
+ kpargs[n++] = '\\';
+ }
+
+ kpargs[n++] = *p++;
+ }
+ }
+
+ /* configure killpath (gil disabled) */
+ Py_BEGIN_ALLOW_THREADS
+ rv = sanlock_killpath(sanlockfd, 0, path, kpargs);
+ Py_END_ALLOW_THREADS
+
+ if (rv != 0) {
+ __set_exception(rv, "Killpath script not configured");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
/* exception_errno */
PyDoc_STRVAR(pydoc_errno, "exception errno");
@@ -572,6 +654,8 @@ sanlock_methods[] = {
METH_VARARGS|METH_KEYWORDS, pydoc_acquire},
{"release", (PyCFunction) py_release,
METH_VARARGS|METH_KEYWORDS, pydoc_release},
+ {"killpath", (PyCFunction) py_killpath,
+ METH_VARARGS|METH_KEYWORDS, pydoc_killpath},
{NULL, NULL, 0, NULL}
};
--
1.7.1
11 years, 9 months
Changes to 'helper'
by David Teigland
New branch 'helper' available with the following commits:
commit 249e661f201f0024a4f8d54c5fce75a60cf08615
Author: David Teigland <teigland(a)redhat.com>
Date: Thu May 24 11:07:17 2012 -0500
daemon: graceful pid handling
Add the "killpath" api to set a program/script for
"killing" a pid/connection, where killing could
be anything that either causes the pid to exit,
or causes the pid to be put into a safe state and
releases its leases, e.g. pausing a vm.
Add a helper process to fork/exec the killpaths.
If pids need to be killed, a configured killpath will
first be run instead of kill(SIGTERM). If the pid
has not exited or had its leases released before
the existing SIGTERM time limit, then sanlock will
escalate to SIGKILL.
This allows for the following:
- pids running with leases in lockspace
- lockspace storage fails (i/o errors, host_id cannot be renewed)
- sanlock runs killpath for each pid
- killpath does inquire, saves state, releases leases
- sanlock finds no more pids with leases in lockspace
- sanlock releases lockspace
- pids remain, but without leases
later:
- lockspace storage is restored
- add_lockspace reacquires host_id
- leases are reacquired for each pid using saved state
- pids running with leases again
This sequence is used by the following test:
cd tests
cp killpath /root/killpath_pause
On host_id 1
./clientn 2 init /dev/bull/leases
./clientn 2 start /dev/bull/leases 1 /root/killpath_pause
./clientn 2 error /dev/bull/leases
./clientn 2 resume /dev/bull/leases 1
If between error and resume, host_id 2 completes:
./clientn 2 start /dev/bull/leases 2 /root/killpath_pause
Then, the resume on host_id 1 will fail and the sanlk_client
pids will be killed.
Signed-off-by: David Teigland <teigland(a)redhat.com>
11 years, 9 months
Changes to 'helper'
by David Teigland
New branch 'helper' available with the following commits:
commit 9736a01b60b0cb380d9b1b14dfdb27b775799101
Author: David Teigland <teigland(a)redhat.com>
Date: Thu May 24 11:07:17 2012 -0500
daemon: graceful pid handling
Add the "killpath" api to set a program/script for
"killing" a pid/connection, where killing could
be anything that either causes the pid to exit,
or causes the pid to be put into a safe state and
releases its leases, e.g. pausing a vm.
Add a helper process to fork/exec the killpaths.
If pids need to be killed, a configured killpath will
first be run instead of kill(SIGTERM). If the pid
has not exited or had its leases released before
the existing SIGTERM time limit, then sanlock will
escalate to SIGKILL.
This allows for the following:
- pids running with leases in lockspace
- lockspace storage fails (i/o errors, host_id cannot be renewed)
- sanlock runs killpath for each pid
- killpath does inquire, saves state, releases leases
- sanlock finds no more pids with leases in lockspace
- sanlock releases lockspace
- pids remain, but without leases
later:
- lockspace storage is restored
- add_lockspace reacquires host_id
- leases are reacquired for each pid using saved state
- pids running with leases again
This sequence is used by the following test:
cd tests
cp killpath /root/killpath_pause
On host_id 1
./clientn 2 init /dev/bull/leases
./clientn 2 start /dev/bull/leases 1 /root/killpath_pause
./clientn 2 error /dev/bull/leases
./clientn 2 resume /dev/bull/leases 1
If between error and resume, host_id 2 completes:
./clientn 2 start /dev/bull/leases 2 /root/killpath_pause
Then, the resume on host_id 1 will fail and the sanlk_client
pids will be killed.
Signed-off-by: David Teigland <teigland(a)redhat.com>
11 years, 9 months
Changes to 'helper'
by David Teigland
New branch 'helper' available with the following commits:
commit 7a371cce94ecc2e594b93c3409483b6ea082379b
Author: David Teigland <teigland(a)redhat.com>
Date: Thu May 24 11:07:17 2012 -0500
daemon: graceful pid handling
Add the "killpath" api to set a program/script for
"killing" a pid/connection, where killing could
be anything that either causes the pid to exit,
or causes the pid to be put into a safe state and
releases its leases, e.g. pausing a vm.
Add a helper process to fork/exec the killpaths.
If pids need to be killed, a configured killpath will
first be run instead of kill(SIGTERM). If the pid
has not exited or had its leases released before
the existing SIGTERM time limit, then sanlock will
escalate to SIGKILL.
This allows for the following:
- pids running with leases in lockspace
- lockspace storage fails (i/o errors, host_id cannot be renewed)
- sanlock runs killpath for each pid
- killpath does inquire, saves state, releases leases
- sanlock finds no more pids with leases in lockspace
- sanlock releases lockspace
- pids remain, but without leases
later:
- lockspace storage is restored
- add_lockspace reacquires host_id
- leases are reacquired for each pid using saved state
- pids running with leases again
This sequence is used by the following test:
cd tests
cp killpath /root/killpath_pause
On host_id 1
./clientn 2 init /dev/bull/leases
./clientn 2 start /dev/bull/leases 1 /root/killpath_pause
./clientn 2 error /dev/bull/leases
./clientn 2 resume /dev/bull/leases 1
If between error and resume, host_id 2 completes:
./clientn 2 start /dev/bull/leases 2 /root/killpath_pause
Then, the resume on host_id 1 will fail and the sanlk_client
pids will be killed.
Signed-off-by: David Teigland <teigland(a)redhat.com>
11 years, 9 months
[PATCH] python: add the support for killpath
by Federico Simoncelli
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
python/sanlock.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 75 insertions(+), 0 deletions(-)
diff --git a/python/sanlock.c b/python/sanlock.c
index d953c90..00d97af 100644
--- a/python/sanlock.c
+++ b/python/sanlock.c
@@ -537,6 +537,79 @@ exit_fail:
return NULL;
}
+/* killpath */
+PyDoc_STRVAR(pydoc_killpath, "\
+killpath(path, args [, slkfd=fd])\n\
+Configure the path and arguments of the executable used to fence a\n\
+process either by causing the pid to exit (kill) or putting it into\n\
+a safe state (resources released).\n\
+The arguments must be in the format: [\"arg1\", \"arg2\", ...]");
+
+static PyObject *
+py_killpath(PyObject *self __unused, PyObject *args, PyObject *keywds)
+{
+ int rv, i, n, num_args, sanlockfd = -1;
+ char *p, *path, kpargs[SANLK_HELPER_ARGS_LEN];
+ PyObject *argslist, *item;
+
+ static char *kwlist[] = {"path", "args", "slkfd", NULL};
+
+ /* parse python tuple */
+ if (!PyArg_ParseTupleAndKeywords(args, keywds, "sO!|i", kwlist,
+ &path, &PyList_Type, &argslist, &sanlockfd)) {
+ return NULL;
+ }
+
+ /* checking the path length */
+ if (strlen(path) + 1 > SANLK_HELPER_PATH_LEN) {
+ __set_exception(EINVAL, "Killpath path argument too long");
+ return NULL;
+ }
+
+ num_args = PyList_Size(argslist);
+ memset(kpargs, 0, SANLK_HELPER_ARGS_LEN);
+
+ /* creating the arguments string from a python list */
+ for (i = 0, n = 0; i < num_args; i++) {
+ size_t arg_len;
+
+ item = PyList_GetItem(argslist, i);
+ p = PyString_AsString(item);
+
+ if (p == NULL) {
+ __set_exception(EINVAL, "Killpath argument not a string");
+ return NULL;
+ }
+
+ /* adding a space between arguments */
+ if (n > 0) {
+ kpargs[n++] = ' ';
+ }
+
+ arg_len = strlen(p);
+
+ if (n + arg_len + 1 > SANLK_HELPER_ARGS_LEN) {
+ __set_exception(EINVAL, "Killpath arguments are too long");
+ return NULL;
+ }
+
+ strncpy(kpargs + n, p, arg_len + 1);
+ n += arg_len;
+ }
+
+ /* configure killpath (gil disabled) */
+ Py_BEGIN_ALLOW_THREADS
+ rv = sanlock_killpath(sanlockfd, 0, path, kpargs);
+ Py_END_ALLOW_THREADS
+
+ if (rv != 0) {
+ __set_exception(rv, "Killpath script not configured");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
/* exception_errno */
PyDoc_STRVAR(pydoc_errno, "exception errno");
@@ -572,6 +645,8 @@ sanlock_methods[] = {
METH_VARARGS|METH_KEYWORDS, pydoc_acquire},
{"release", (PyCFunction) py_release,
METH_VARARGS|METH_KEYWORDS, pydoc_release},
+ {"killpath", (PyCFunction) py_killpath,
+ METH_VARARGS|METH_KEYWORDS, pydoc_killpath},
{NULL, NULL, 0, NULL}
};
--
1.7.1
11 years, 9 months