chroot: Create all paths first, then mount

We mounted after creating dirs, this was potentially problematic
for the next path policy to follow.

Perform two passes on the path_policies list, first creates all
dirs, second does the mounts.
This commit is contained in:
Albert S. 2022-01-08 15:04:15 +01:00
parent 3b61e90761
commit a9e6b3ee67

77
exile.h
Vedi File

@ -1092,28 +1092,39 @@ static int path_policy_needs_landlock(struct exile_path_policy *path_policy)
return 0; return 0;
} }
/* Helper to mount directories into the chroot path "chroot_target_path" /* TODO: we can do va_args */
* Paths will be created if necessary char *concat_path(const char *first, const char *second)
* @returns: 0 on sucess, -ERRNO on failure */
static int mount_to_chroot(const char *chroot_target_path, struct exile_path_policy *path_policy)
{ {
while(path_policy != NULL) char *result = (char *) calloc(1, PATH_MAX);
if(result == NULL)
{ {
EXILE_LOG_ERROR("exile: concat_path: calloc failed\n");
char path_inside_chroot[PATH_MAX]; return NULL;
int written = snprintf(path_inside_chroot, sizeof(path_inside_chroot), "%s/%s", chroot_target_path, path_policy->path); }
//TODO: We can strip multiple redundant slashes
int written = snprintf(result, PATH_MAX, "%s/%s", first, second);
if(written < 0) if(written < 0)
{ {
EXILE_LOG_ERROR("exile: mount_to_chroot: Error during path concatination\n"); EXILE_LOG_ERROR("exile: concat_path: Error during path concatination\n");
return -EINVAL; return NULL;
} }
if(written >= PATH_MAX) if(written >= PATH_MAX)
{ {
EXILE_LOG_ERROR("exile: mount_to_chroot: path concatination truncated\n"); EXILE_LOG_ERROR("exile: mount_to_chroot: path concatination truncated\n");
return -EINVAL; return NULL;
}
return result;
} }
/* Helper to mount directories into the chroot path "chroot_target_path"
* Paths will be created if necessary
* @returns: 0 on sucess, -ERRNO on failure */
static int create_chroot_dirs(const char *chroot_target_path, struct exile_path_policy *path_policy)
{
while(path_policy != NULL)
{
struct stat sb; struct stat sb;
int ret = stat(path_policy->path, &sb); int ret = stat(path_policy->path, &sb);
if(ret < 0) if(ret < 0)
@ -1127,25 +1138,48 @@ static int mount_to_chroot(const char *chroot_target_path, struct exile_path_pol
{ {
baseisfile = 1; baseisfile = 1;
} }
char *path_inside_chroot = concat_path(chroot_target_path, path_policy->path);
if(path_inside_chroot == NULL)
{
return 1;
}
ret = mkpath(path_inside_chroot, 0700, baseisfile); ret = mkpath(path_inside_chroot, 0700, baseisfile);
if(ret < 0) if(ret < 0)
{ {
EXILE_LOG_ERROR("Error creating directory structure while mounting paths to chroot. %s\n", strerror(errno)); EXILE_LOG_ERROR("Error creating directory structure while mounting paths to chroot. %s\n", strerror(errno));
free(path_inside_chroot);
return ret; return ret;
} }
path_policy = path_policy->next;
free(path_inside_chroot);
}
return 0;
}
static int perform_mounts(const char *chroot_target_path, struct exile_path_policy *path_policy)
{
while(path_policy != NULL)
{
int mount_flags = get_policy_mount_flags(path_policy); int mount_flags = get_policy_mount_flags(path_policy);
char *path_inside_chroot = concat_path(chroot_target_path, path_policy->path);
if(path_inside_chroot == NULL)
{
return 1;
}
//all we do is bind mounts //all we do is bind mounts
mount_flags |= MS_BIND; mount_flags |= MS_BIND;
if(path_policy->policy & EXILE_FS_ALLOW_ALL_READ || path_policy->policy & EXILE_FS_ALLOW_ALL_WRITE) if(path_policy->policy & EXILE_FS_ALLOW_ALL_READ || path_policy->policy & EXILE_FS_ALLOW_ALL_WRITE)
{ {
ret = mount(path_policy->path, path_inside_chroot, NULL, mount_flags, NULL); int ret = mount(path_policy->path, path_inside_chroot, NULL, mount_flags, NULL);
if(ret < 0 ) if(ret < 0 )
{ {
EXILE_LOG_ERROR("Error: Failed to mount %s to %s: %s\n", path_policy->path, path_inside_chroot, strerror(errno)); EXILE_LOG_ERROR("Error: Failed to mount %s to %s: %s\n", path_policy->path, path_inside_chroot, strerror(errno));
free(path_inside_chroot);
return ret; return ret;
} }
@ -1154,15 +1188,18 @@ static int mount_to_chroot(const char *chroot_target_path, struct exile_path_pol
if(ret < 0 ) if(ret < 0 )
{ {
EXILE_LOG_ERROR("Error: Failed to remount %s: %s\n", path_inside_chroot, strerror(errno)); EXILE_LOG_ERROR("Error: Failed to remount %s: %s\n", path_inside_chroot, strerror(errno));
free(path_inside_chroot);
return ret; return ret;
} }
}
path_policy = path_policy->next; path_policy = path_policy->next;
free(path_inside_chroot);
}
} }
return 0; return 0;
} }
/* /*
* Frees the memory taken by a exile_policy object * Frees the memory taken by a exile_policy object
*/ */
@ -1767,11 +1804,17 @@ int exile_enable_policy(struct exile_policy *policy)
} }
} }
if(mount_to_chroot(policy->chroot_target_path, policy->path_policies) < 0) if(create_chroot_dirs(policy->chroot_target_path, policy->path_policies) < 0)
{ {
EXILE_LOG_ERROR("mount_to_chroot: bind mounting of path policies failed\n"); EXILE_LOG_ERROR("mount_to_chroot: bind mounting of path policies failed\n");
return -1; return -1;
} }
if(perform_mounts(policy->chroot_target_path, policy->path_policies) < 0)
{
EXILE_LOG_ERROR("perform_mounts: Failed to remount\n");
return -1;
}
} }
if(*policy->chroot_target_path != '\0') if(*policy->chroot_target_path != '\0')