Skip to content

Loading…

Sources chroot #1054

Merged
merged 2 commits into from

1 participant

@skinkie
Cherokee Project member

Fix #646

skinkie added some commits
@skinkie skinkie Merge chroot for interpreters RFE
In 2010 @dennmart implemented a patch for interpreters which allow
them to chroot. This patch was provided in:

http://code.google.com/p/cherokee/issues/detail?id=767 (GitHub #646)

Thanks a million for giving us a reference!
bbf78b8
@skinkie skinkie Update the documentation numbers, and phase. ba31031
@skinkie skinkie merged commit 281ad1d into master
@skinkie skinkie deleted the sources_chroot branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 30, 2013
  1. @skinkie

    Merge chroot for interpreters RFE

    skinkie committed
    In 2010 @dennmart implemented a patch for interpreters which allow
    them to chroot. This patch was provided in:
    
    http://code.google.com/p/cherokee/issues/detail?id=767 (GitHub #646)
    
    Thanks a million for giving us a reference!
  2. @skinkie
View
2 admin/PageSource.py
@@ -52,6 +52,7 @@
NOTE_USAGE = N_('Sources currently in use. Note that the last source of any rule cannot be deleted until the rule has been manually edited.')
NOTE_USER = N_('Execute the interpreter under a different user. Default: Same UID as the server.')
NOTE_GROUP = N_('Execute the interpreter under a different group. Default: Default GID of the new process UID.')
+NOTE_CHROOT = N_('Execute the interpreter under a different root. Default: no.')
NOTE_ENV_INHERIT = N_('Whether the new child process should inherit the environment variables from the server process. Default: yes.')
NOTE_DELETE_DIALOG = N_('You are about to delete an Information Source. Are you sure you want to proceed?')
NOTE_NO_ENTRIES = N_('The Information Source list is currently empty.')
@@ -291,6 +292,7 @@ def __call__ (self):
table.Add (_('Spawning timeout'), CTK.TextCfg ('source!%s!timeout'%(num), True), _(NOTE_TIMEOUT))
table.Add (_('Execute as User'), CTK.TextCfg ('source!%s!user'%(num), True), _(NOTE_USER))
table.Add (_('Execute as Group'), CTK.TextCfg ('source!%s!group'%(num), True), _(NOTE_GROUP))
+ table.Add (_('Chroot Directory'), CTK.TextCfg ('source!%s!chroot'%(num), True), _(NOTE_CHROOT))
table.Add (_('Inherit Environment'), CTK.CheckCfgText ('source!%s!env_inherited'%(num), True, _('Enabled')), _(NOTE_ENV_INHERIT))
submit = CTK.Submitter (URL_APPLY)
View
17 admin/SavingChecks.py
@@ -56,15 +56,30 @@ def check_config():
for s in CTK.cfg['source'] or []:
sourcetype = CTK.cfg.get_val ('source!%s!type'%(s))
interpreter = CTK.cfg.get_val ('source!%s!interpreter'%(s))
+ chroot = CTK.cfg.get_val ('source!%s!chroot'%(s))
if sourcetype == 'interpreter':
if (not CTK.cfg.get_val ('source!%s!interpreter'%(s)) or \
interpreter.strip() == ''):
errors.append (Error(_('Source without Interpreter'),
'/source/%s'%(s)))
+
+ if chroot:
+ if chroot[0] != '/':
+ errors.append (Error(_('Chroot folder is not an absolute path'),
+ '/source/%s'%(s)))
+ else:
+ if not os.path.exists(chroot):
+ errors.append (Error(_('Chroot folder does not exist'),
+ '/source/%s'%(s)))
+
+ elif not os.path.exists(chroot+interpreter.split(' ')[0]):
+ errors.append (Error(_('Interpreter does not exist inside chroot'),
+ '/source/%s'%(s)))
+
elif not os.path.exists(interpreter.split(' ')[0]):
errors.append (Error(_('Interpreter does not exist'),
- '/source/%s'%(s)))
+ '/source/%s'%(s)))
#
# Validators without Realm
View
3 cherokee/error_list.py
@@ -752,6 +752,9 @@
title = "Could not spawn '%s'",
desc = SYSTEM_ISSUE)
+e('SRC_INTER_CHROOT',
+ title = "Could not chroot() to '%s'",
+ desc = SYSTEM_ISSUE)
# cherokee/config_reader.c
#
View
34 cherokee/main.c
@@ -438,6 +438,7 @@ do_spawn (void)
char *interpreter = NULL;
char *log_file = NULL;
char *uid_str = NULL;
+ char *chroot_dir = NULL;
char **envp = NULL;
char *p = spawn_shared;
const char *argv[] = {"sh", "-c", NULL, NULL};
@@ -488,8 +489,19 @@ do_spawn (void)
memcpy (&gid, p, sizeof(gid_t));
p += sizeof(gid_t);
- /* 3.- Environment */
+ /* 3.- Chroot directory */
CHECK_MARK (0xF2);
+ size = *((int *) p);
+ p += sizeof(int);
+ if (size > 0) {
+ chroot_dir = malloc(size + 1);
+ memcpy(chroot_dir, p, size + 1);
+ }
+ p += size + 1;
+ ALIGN4 (p);
+
+ /* 4.- Environment */
+ CHECK_MARK (0xF3);
env_inherit = *((int *)p);
p += sizeof(int);
@@ -522,8 +534,8 @@ do_spawn (void)
ALIGN4 (p);
}
- /* 4.- Error log */
- CHECK_MARK (0xF3);
+ /* 5.- Error log */
+ CHECK_MARK (0xF4);
size = *((int *)p);
p += sizeof(int);
@@ -539,8 +551,8 @@ do_spawn (void)
ALIGN4 (p);
}
- /* 5.- PID: it's -1 now */
- CHECK_MARK (0xF4);
+ /* 6.- PID: it's -1 now */
+ CHECK_MARK (0xF5);
n = *((int *)p);
if (n > 0) {
@@ -588,6 +600,15 @@ do_spawn (void)
dup2 (tmp_fd, STDERR_FILENO);
}
+ /* Change root */
+ if (chroot_dir) {
+ int re = chroot(chroot_dir);
+ if (re < 0) {
+ PRINT_ERROR ("(critial) Couldn't chroot to %s\n", chroot_dir);
+ exit (1);
+ }
+ }
+
/* Change user & group */
if (uid_str != NULL) {
n = initgroups (uid_str, gid);
@@ -643,7 +664,7 @@ do_spawn (void)
/* Return the PID
*/
memcpy (p, (char *)&child, sizeof(int));
- printf ("PID %d: launched '/bin/sh -c %s' with uid=%d, gid=%d, env=%s\n", child, interpreter, uid, gid, env_inherit ? "inherited":"custom");
+ printf ("PID %d: launched '/bin/sh -c %s' with uid=%d, gid=%d, chroot=%s, env=%s\n", child, interpreter, uid, gid, chroot_dir, env_inherit ? "inherited":"custom");
cleanup:
/* Unlock worker
@@ -654,6 +675,7 @@ do_spawn (void)
*/
free (uid_str);
free (interpreter);
+ free (chroot_dir);
if (envp != NULL) {
for (n=0; n<envs; n++) {
View
52 cherokee/source_interpreter.c
@@ -54,6 +54,7 @@ cherokee_source_interpreter_new (cherokee_source_interpreter_t **src)
cherokee_source_init (SOURCE(n));
cherokee_buffer_init (&n->interpreter);
cherokee_buffer_init (&n->change_user_name);
+ cherokee_buffer_init (&n->chroot);
n->custom_env = NULL;
n->custom_env_len = 0;
@@ -115,6 +116,7 @@ interpreter_free (void *ptr)
cherokee_buffer_mrproper (&src->interpreter);
cherokee_buffer_mrproper (&src->change_user_name);
+ cherokee_buffer_mrproper (&src->chroot);
if (src->custom_env)
free_custom_env (src);
@@ -143,17 +145,30 @@ find_next_stop (char *p)
}
static ret_t
-check_interpreter_full (cherokee_buffer_t *fullpath)
+check_interpreter_full (cherokee_buffer_t *fullpath, cherokee_buffer_t *chroot_dir)
{
+ ret_t ret = ret_error;
int re;
struct stat inter;
char *p;
char tmp;
- const char *end = fullpath->buf + fullpath->len;
+ const char *end;
+ cherokee_buffer_t completepath = CHEROKEE_BUF_INIT;
- p = find_next_stop (fullpath->buf + 1);
+ cherokee_buffer_clean(&completepath);
+ if (chroot_dir->len > 0) {
+ /* Chroot and relative path, it doesn't make sense */
+ if (fullpath->len == 0 || fullpath->buf[0] != '/')
+ goto done;
+
+ cherokee_buffer_add_buffer (&completepath, chroot_dir);
+ }
+ cherokee_buffer_add_buffer(&completepath, fullpath);
+ end = completepath.buf + completepath.len;
+
+ p = find_next_stop (completepath.buf + 1);
if (p == NULL)
- return ret_error;
+ goto done;
while (p <= end) {
/* Set a temporal end */
@@ -161,12 +176,13 @@ check_interpreter_full (cherokee_buffer_t *fullpath)
*p = '\0';
/* Does the file exist? */
- re = cherokee_stat (fullpath->buf, &inter);
+ re = cherokee_stat (completepath.buf, &inter);
if ((re == 0) &&
(! S_ISDIR(inter.st_mode)))
{
*p = tmp;
- return ret_ok;
+ ret = ret_ok;
+ goto done;
}
*p = tmp;
@@ -181,12 +197,14 @@ check_interpreter_full (cherokee_buffer_t *fullpath)
p = (char *)end;
}
- return ret_error;
+done:
+ cherokee_buffer_mrproper(&completepath);
+ return ret;
}
static ret_t
-check_interpreter_path (cherokee_buffer_t *partial_path)
+check_interpreter_path (cherokee_buffer_t *partial_path, cherokee_buffer_t *chroot_dir)
{
ret_t ret;
char *p;
@@ -213,7 +231,7 @@ check_interpreter_path (cherokee_buffer_t *partial_path)
cherokee_buffer_add_char (&fullpath, '/');
cherokee_buffer_add_buffer (&fullpath, partial_path);
- ret = check_interpreter_full (&fullpath);
+ ret = check_interpreter_full (&fullpath, chroot_dir);
if (ret == ret_ok)
goto done;
@@ -256,9 +274,9 @@ check_interpreter (cherokee_source_interpreter_t *src)
ret_t ret;
if (src->interpreter.buf[0] == '/') {
- ret = check_interpreter_full (&src->interpreter);
+ ret = check_interpreter_full (&src->interpreter, &src->chroot);
} else {
- ret = check_interpreter_path (&src->interpreter);
+ ret = check_interpreter_path (&src->interpreter, &src->chroot);
}
return ret;
@@ -438,6 +456,9 @@ cherokee_source_interpreter_configure (cherokee_source_interpreter_t *src,
src->change_group = grp.gr_gid;
+ } else if (equal_buf_str (&child->key, "chroot")) {
+ cherokee_buffer_add_buffer (&src->chroot, &child->val);
+
} else if (equal_buf_str (&child->key, "env")) {
cherokee_config_node_foreach (j, child) {
cherokee_config_node_t *child2 = CONFIG_NODE(j);
@@ -514,6 +535,7 @@ _spawn_shm (cherokee_source_interpreter_t *src,
&src->change_user_name,
src->change_user,
src->change_group,
+ &src->chroot,
src->env_inherited,
envp,
error_writer,
@@ -600,6 +622,14 @@ _spawn_local (cherokee_source_interpreter_t *src,
}
}
+ if (src->chroot.len > 0) {
+ re = chroot(src->chroot.buf);
+ if (re < 0) {
+ LOG_ERROR (CHEROKEE_ERROR_SRC_INTER_CHROOT, src->chroot.buf);
+ exit(1);
+ }
+ }
+
argv[2] = (char *)tmp.buf;
if (src->env_inherited) {
do {
View
1 cherokee/source_interpreter.h
@@ -39,6 +39,7 @@ typedef enum {
typedef struct {
cherokee_source_t source;
cherokee_buffer_t interpreter;
+ cherokee_buffer_t chroot;
cherokee_boolean_t env_inherited;
char **custom_env;
View
18 cherokee/spawner.c
@@ -187,6 +187,7 @@ cherokee_spawner_spawn (cherokee_buffer_t *binary,
cherokee_buffer_t *user,
uid_t uid,
gid_t gid,
+ cherokee_buffer_t *chroot,
int env_inherited,
char **envp,
cherokee_logger_writer_t *error_writer,
@@ -247,9 +248,16 @@ cherokee_spawner_spawn (cherokee_buffer_t *binary,
cherokee_buffer_add (&tmp, (char *)&uid, sizeof(uid_t));
cherokee_buffer_add (&tmp, (char *)&gid, sizeof(gid_t));
- /* 3.- Environment */
+ /* 3.- Chroot directory */
phase = 0xF2;
cherokee_buffer_add (&tmp, (char *)&phase, sizeof(int));
+ cherokee_buffer_add (&tmp, (char *)&chroot->len, sizeof(int));
+ cherokee_buffer_add_buffer (&tmp, chroot);
+ cherokee_buffer_add_char (&tmp, '\0');
+
+ /* 4.- Environment */
+ phase = 0xF3;
+ cherokee_buffer_add (&tmp, (char *)&phase, sizeof(int));
for (n=envp; *n; n++) {
envs ++;
@@ -266,15 +274,15 @@ cherokee_spawner_spawn (cherokee_buffer_t *binary,
ALIGN4(tmp);
}
- /* 4.- Error log */
- phase = 0xF3;
+ /* 5.- Error log */
+ phase = 0xF4;
cherokee_buffer_add (&tmp, (char *)&phase, sizeof(int));
write_logger (&tmp, error_writer);
ALIGN4 (tmp);
- /* 5.- PID (will be rewritten by the other side) */
- phase = 0xF4;
+ /* 6.- PID (will be rewritten by the other side) */
+ phase = 0xF5;
cherokee_buffer_add (&tmp, (char *)&phase, sizeof(int));
pid_shm = (int *) (((char *)cherokee_spawn_shared.mem) + tmp.len);
View
1 cherokee/spawner.h
@@ -57,6 +57,7 @@ ret_t cherokee_spawner_spawn (cherokee_buffer_t *binary,
cherokee_buffer_t *user_name,
uid_t uid,
gid_t gid,
+ cherokee_buffer_t *chroot,
int env_inherited,
char **envp,
cherokee_logger_writer_t *error_writer,
Something went wrong with that request. Please try again.