Déan comparáid idir tiomáintí
9 Tiomáintí
bbbdfc44da
...
next
Údar | SHA1 | Dáta | |
---|---|---|---|
40d23af355 | |||
b5f83499f3 | |||
ff60ec227d | |||
e711a1d53a | |||
6628bf4fb7 | |||
3fa73b0b97 | |||
8f38dc4480 | |||
42d44b0cc1 | |||
bd3641981c |
38
README.md
38
README.md
@ -1,6 +1,5 @@
|
|||||||
# exile.h
|
# exile.h
|
||||||
`exile.h` is a header-only library, enabling processes to easily isolate themselves on Linux for exploit mitigation purposes. exile.h wants to make existing technologies, such as Seccomp and Linux Namespaces, easier to use. Those generally
|
`exile.h` provides an API for processes on Linux to easily isolate themselves for exploit mitigation purposes. exile.h makes it simpler for developers to use existing technologies such as Seccomp and Linux Namespaces. Those generally require knowledge of details and are not trivial for developers to employ, which prevents a more widespread adoption.
|
||||||
require knowledge of details and are not trivial for developers to employ, which prevents a more widespread adoption.
|
|
||||||
|
|
||||||
The following section offers small examples. Then the motivation is explained in more detail.
|
The following section offers small examples. Then the motivation is explained in more detail.
|
||||||
Proper API documentation will be maintained in other files.
|
Proper API documentation will be maintained in other files.
|
||||||
@ -11,7 +10,7 @@ a first impression.
|
|||||||
|
|
||||||
system() is used to keep the example C code short. It also demonstrates that subprocesses are also subject to restrictions imposed by exile.h.
|
system() is used to keep the example C code short. It also demonstrates that subprocesses are also subject to restrictions imposed by exile.h.
|
||||||
|
|
||||||
While the example show different features separately, it is generally possible to combine those.
|
While the examples show different features separately, it is generally possible to combine those.
|
||||||
|
|
||||||
### Filesystem isolation
|
### Filesystem isolation
|
||||||
```c
|
```c
|
||||||
@ -43,8 +42,8 @@ int main(void)
|
|||||||
The assert() calls won't be fired, consistent with the policy.
|
The assert() calls won't be fired, consistent with the policy.
|
||||||
|
|
||||||
### System call policies / vows
|
### System call policies / vows
|
||||||
exile.h allows specifying which syscalls are permitted or denied. In the folloing example,
|
exile.h allows specifying which syscalls are permitted or denied. In the following example,
|
||||||
ls is never executed, as the specificed "vows" do not allow the execve() system call. The
|
'ls' is never executed, as the specified "vows" do not allow the execve() system call. The
|
||||||
process will be killed.
|
process will be killed.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
@ -130,37 +129,27 @@ the subprocess "cat()" was launched in violated the policy (missing "rpath" vow)
|
|||||||
Naturally, there is a performance overhead. Certain challenges remain, such as the fact
|
Naturally, there is a performance overhead. Certain challenges remain, such as the fact
|
||||||
that being executed in a subprocess, we operate on copies, so handling references
|
that being executed in a subprocess, we operate on copies, so handling references
|
||||||
is not something that has been given much thought. There is also the fact
|
is not something that has been given much thought. There is also the fact
|
||||||
that clone()ing from threads opens a can of worms. Hence, exile_launch()
|
that clone()ing from threads opens a can of worms, particularly with locks. Hence, exile_launch()
|
||||||
is best avoided in multi-threaded contexts.
|
is best avoided in multi-threaded contexts.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
No release yet, experimental, API is unstable, builds will break on updates of this library.
|
No release yet, experimental, API is unstable, builds will break on updates of this library.
|
||||||
|
|
||||||
Currently, it's mainly evolving from the needs of my other projects.
|
Currently, it's mainly evolving from the needs of my other projects which use exile.h.
|
||||||
|
|
||||||
## Motivation and Background
|
## Motivation and Background
|
||||||
exile.h unlocks existing Linux mechanisms to facilite isolation of processes from resources. Limiting the scope of what programs can do helps defending the rest of the system when a process gets under attacker's control (when classic mitigations such as ASLR etc. failed). To this end, OpenBSD has the pledge() and unveil() functions available. Those functions are helpful mitigation mechanisms, but such accessible ways are unfortunately not readily available on Linux. This is where exile.h steps in.
|
exile.h unlocks existing Linux mechanisms to facilitate isolation of processes from resources. Limiting the scope of what programs can do helps defending the rest of the system when a process gets under attacker's control (when classic mitigations such as ASLR etc. failed). To this end, OpenBSD has the pledge() and unveil() functions available. Those functions are helpful mitigation mechanisms, but such accessible ways are unfortunately not readily available on Linux. This is where exile.h steps in.
|
||||||
|
|
||||||
Seccomp allows restricting the system calls available to a process and thus decrease the systems attack surface, but it generally is not easy to use. Requiring BPF filter instructions, you generally just can't make use of it right away. exile.h provides an API inspired by pledge(), building on top of seccomp. It also provides an interface to manually restrict the system calls that can be issued.
|
Seccomp allows restricting the system calls available to a process and thus decrease the systems attack surface, but it generally is not easy to use. Requiring BPF filter instructions, you generally just can't make use of it right away. exile.h provides an API inspired by pledge(), building on top of seccomp. It also provides an interface to manually restrict the system calls that can be issued.
|
||||||
|
|
||||||
Traditional methods employed to restrict file system access, like different uids/gids, chroot, bind-mounts, namespaces etc. may require administrator intervention, are perhaps only suitable
|
Traditional methods employed to restrict file system access, like different uids/gids, chroot, bind-mounts, namespaces etc. may require administrator intervention, are perhaps only suitable
|
||||||
for daemons and not desktop applications, or are generally rather involved. As a positive example, Landlock since 5.13 is a vast improvement to limit file system access of processes. It also greatly simplifies exile.h' implementation of fs isolation.
|
for daemons and not desktop applications, or are generally rather involved. As a positive example, Landlock since 5.13 is a vast improvement to limit file system access of processes. It also greatly simplifies exile.h' implementation of fs isolation.
|
||||||
|
|
||||||
Abstracting those details may help developers bring sandboxing into their applications.
|
Abstracting those details may help developers bring sandboxing into their applications.
|
||||||
|
|
||||||
## Example: Archive extraction
|
|
||||||
A programming uncompressing archives does not need network access, but should a bug allow code execution, obviously the payload may also access the network. Once the target path is known, it doesn't need access to the whole file system, only write-permissions to the target directory and read on the archive file(s).
|
|
||||||
|
|
||||||
TODO example with exile.h applied on "tar" or "unzip". Link to repo.
|
|
||||||
|
|
||||||
## Example: Web apps
|
|
||||||
Those generally don't need access to the whole filesystem hierarchy, nor do they necessarily require the ability to execute other processes.
|
|
||||||
|
|
||||||
Way more examples can be given, but we can put it in simple words: A general purpose OS allow a process to do more things than it actually needs to do.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Restricting file system access (using Landlock or Namespaces/chroot as fallback)
|
- Restricting file system access (using Landlock or Namespaces/chroot as fallback)
|
||||||
- Systemcall filtering (using seccomp-bpf). An interface inspired by OpenBSD's pledge() is available, removing the need to specifc rules for syscalls.
|
- Systemcall filtering (using seccomp-bpf). An interface inspired by OpenBSD's pledge() is available
|
||||||
- Dropping privileges in general, such as capabilities
|
- Dropping privileges in general, such as capabilities
|
||||||
- Isolating the application from the network, etc. through Namespaces
|
- Isolating the application from the network, etc. through Namespaces
|
||||||
- Helpers to isolate single functions
|
- Helpers to isolate single functions
|
||||||
@ -191,13 +180,13 @@ TODO:
|
|||||||
## Requirements
|
## Requirements
|
||||||
Kernel >=3.17
|
Kernel >=3.17
|
||||||
|
|
||||||
While mostly transparent to users of this API, kernel >= 5.13 is required to take advantage of Landlock. Furthermore, it depends on distro-provided kernels being reasonable and enabling it by default. In practise, this means that Landlock probably won't be used for now, and exile.h will use a combination of namespaces, bind mounts and chroot as fallbacks.
|
While mostly transparent to users of this API, kernel >= 5.13 is required to take advantage of Landlock. Furthermore, it depends on distro-provided kernels being reasonable and enabling it by default. In practise, Landlock maybe won't be used in some cases so exile.h will use a combination of namespaces, bind mounts and chroot as fallbacks.
|
||||||
|
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
|
|
||||||
### Does the process need to be priviliged to utilize the library?
|
### Does the process need to be privileged to utilize the library?
|
||||||
|
|
||||||
No.
|
No.
|
||||||
|
|
||||||
@ -208,13 +197,16 @@ You can thank a Debian-specific kernel patch for that. Execute
|
|||||||
Note that newer releases should not cause this problem any longer, as [explained](https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html#linux-user-namespaces) in the Debian release notes.
|
Note that newer releases should not cause this problem any longer, as [explained](https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html#linux-user-namespaces) in the Debian release notes.
|
||||||
|
|
||||||
### Real-world usage
|
### Real-world usage
|
||||||
- looqs: https://gitea.quitesimple.org/crtxcr/looqs
|
- looqs: https://github.com/quitesimpleorg/looqs
|
||||||
- qswiki: https://gitea.quitesimple.org/crtxcr/qswiki
|
- qswiki: https://gitea.quitesimple.org/crtxcr/qswiki
|
||||||
|
|
||||||
Outdated:
|
Outdated:
|
||||||
- cgit sandboxed: https://gitea.quitesimple.org/crtxcr/cgitsb
|
- cgit sandboxed: https://gitea.quitesimple.org/crtxcr/cgitsb
|
||||||
- qpdfviewsb sandboxed (quick and dirty): https://gitea.quitesimple.org/crtxcr/qpdfviewsb
|
- qpdfviewsb sandboxed (quick and dirty): https://gitea.quitesimple.org/crtxcr/qpdfviewsb
|
||||||
|
|
||||||
|
### Other projects
|
||||||
|
- [sandbox2](https://developers.google.com/code-sandboxing/sandbox2/)
|
||||||
|
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
||||||
|
72
exile.c
72
exile.c
@ -280,7 +280,7 @@ static struct syscall_vow_map exile_vow_map[] =
|
|||||||
{EXILE_SYS(copy_file_range), EXILE_SYSCALL_VOW_STDIO},
|
{EXILE_SYS(copy_file_range), EXILE_SYSCALL_VOW_STDIO},
|
||||||
{EXILE_SYS(statx), EXILE_SYSCALL_VOW_RPATH},
|
{EXILE_SYS(statx), EXILE_SYSCALL_VOW_RPATH},
|
||||||
{EXILE_SYS(rseq), EXILE_SYSCALL_VOW_THREAD},
|
{EXILE_SYS(rseq), EXILE_SYSCALL_VOW_THREAD},
|
||||||
{EXILE_SYS(clone3), EXILE_SYSCALL_VOW_CLONE},
|
{EXILE_SYS(clone3), EXILE_SYSCALL_VOW_CLONE|EXILE_SYSCALL_VOW_THREAD},
|
||||||
{EXILE_SYS(close_range), EXILE_SYSCALL_VOW_STDIO},
|
{EXILE_SYS(close_range), EXILE_SYSCALL_VOW_STDIO},
|
||||||
{EXILE_SYS(openat2), EXILE_SYSCALL_VOW_RPATH|EXILE_SYSCALL_VOW_WPATH},
|
{EXILE_SYS(openat2), EXILE_SYSCALL_VOW_RPATH|EXILE_SYSCALL_VOW_WPATH},
|
||||||
{EXILE_SYS(faccessat2), EXILE_SYSCALL_VOW_RPATH},
|
{EXILE_SYS(faccessat2), EXILE_SYSCALL_VOW_RPATH},
|
||||||
@ -361,10 +361,11 @@ inline int exile_landlock_is_available()
|
|||||||
{
|
{
|
||||||
#if HAVE_LANDLOCK == 1
|
#if HAVE_LANDLOCK == 1
|
||||||
int ruleset = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
|
int ruleset = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
|
||||||
return ruleset == 1;
|
return ruleset > 0;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int exile_append_syscall_policy(struct exile_policy *exile_policy, long syscall, unsigned int syscall_policy, struct sock_filter *argfilters, size_t n)
|
int exile_append_syscall_policy(struct exile_policy *exile_policy, long syscall, unsigned int syscall_policy, struct sock_filter *argfilters, size_t n)
|
||||||
{
|
{
|
||||||
struct exile_syscall_policy *newpolicy = (struct exile_syscall_policy *) calloc(1, sizeof(struct exile_syscall_policy));
|
struct exile_syscall_policy *newpolicy = (struct exile_syscall_policy *) calloc(1, sizeof(struct exile_syscall_policy));
|
||||||
@ -381,6 +382,7 @@ int exile_append_syscall_policy(struct exile_policy *exile_policy, long syscall,
|
|||||||
{
|
{
|
||||||
EXILE_LOG_ERROR("Too many argfilters supplied\n");
|
EXILE_LOG_ERROR("Too many argfilters supplied\n");
|
||||||
exile_policy->exile_flags |= EXILE_FLAG_ADD_SYSCALL_POLICY_FAIL;
|
exile_policy->exile_flags |= EXILE_FLAG_ADD_SYSCALL_POLICY_FAIL;
|
||||||
|
free(newpolicy);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for(size_t i = 0; i < n; i++)
|
for(size_t i = 0; i < n; i++)
|
||||||
@ -388,10 +390,10 @@ int exile_append_syscall_policy(struct exile_policy *exile_policy, long syscall,
|
|||||||
newpolicy->argfilters[i] = argfilters[i];
|
newpolicy->argfilters[i] = argfilters[i];
|
||||||
}
|
}
|
||||||
newpolicy->next = NULL;
|
newpolicy->next = NULL;
|
||||||
|
|
||||||
*(exile_policy->syscall_policies_tail) = newpolicy;
|
*(exile_policy->syscall_policies_tail) = newpolicy;
|
||||||
exile_policy->syscall_policies_tail = &(newpolicy->next);
|
exile_policy->syscall_policies_tail = &(newpolicy->next);
|
||||||
|
|
||||||
exile_policy->disable_syscall_filter = 0;
|
exile_policy->disable_syscall_filter = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -521,7 +523,7 @@ int get_vow_argfilter(long syscall, uint64_t vow_promises, struct sock_filter *f
|
|||||||
current_count = COUNT_EXILE_SYSCALL_FILTER(open_filter);
|
current_count = COUNT_EXILE_SYSCALL_FILTER(open_filter);
|
||||||
break;
|
break;
|
||||||
case EXILE_SYS(openat2):
|
case EXILE_SYS(openat2):
|
||||||
*policy = EXILE_SYSCALL_DENY_RET_ERROR;
|
*policy = EXILE_SYSCALL_DENY_RET_NOSYS;
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case EXILE_SYS(socket):
|
case EXILE_SYS(socket):
|
||||||
@ -539,7 +541,7 @@ int get_vow_argfilter(long syscall, uint64_t vow_promises, struct sock_filter *f
|
|||||||
case EXILE_SYS(clone3):
|
case EXILE_SYS(clone3):
|
||||||
if((vow_promises & EXILE_SYSCALL_VOW_CLONE) == 0)
|
if((vow_promises & EXILE_SYSCALL_VOW_CLONE) == 0)
|
||||||
{
|
{
|
||||||
*policy = EXILE_SYSCALL_DENY_RET_ERROR;
|
*policy = EXILE_SYSCALL_DENY_RET_NOSYS;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -814,11 +816,13 @@ char *concat_path(const char *first, const char *second)
|
|||||||
if(written < 0)
|
if(written < 0)
|
||||||
{
|
{
|
||||||
EXILE_LOG_ERROR("Error during path concatination\n");
|
EXILE_LOG_ERROR("Error during path concatination\n");
|
||||||
|
free(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(written >= PATH_MAX)
|
if(written >= PATH_MAX)
|
||||||
{
|
{
|
||||||
EXILE_LOG_ERROR("path concatination truncated\n");
|
EXILE_LOG_ERROR("path concatination truncated\n");
|
||||||
|
free(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -869,18 +873,18 @@ static int perform_mounts(const char *chroot_target_path, struct exile_path_poli
|
|||||||
{
|
{
|
||||||
while(path_policy != NULL)
|
while(path_policy != NULL)
|
||||||
{
|
{
|
||||||
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
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
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
|
||||||
|
mount_flags |= MS_BIND;
|
||||||
|
|
||||||
int 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 )
|
||||||
{
|
{
|
||||||
@ -897,9 +901,10 @@ static int perform_mounts(const char *chroot_target_path, struct exile_path_poli
|
|||||||
free(path_inside_chroot);
|
free(path_inside_chroot);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
path_policy = path_policy->next;
|
|
||||||
free(path_inside_chroot);
|
free(path_inside_chroot);
|
||||||
}
|
}
|
||||||
|
path_policy = path_policy->next;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1075,6 +1080,10 @@ static struct sock_filter *append_syscall_to_bpf(struct exile_syscall_policy *sy
|
|||||||
{
|
{
|
||||||
action = SECCOMP_RET_ERRNO|EACCES;
|
action = SECCOMP_RET_ERRNO|EACCES;
|
||||||
}
|
}
|
||||||
|
if(action == EXILE_SYSCALL_DENY_RET_NOSYS)
|
||||||
|
{
|
||||||
|
action = SECCOMP_RET_ERRNO|ENOSYS;
|
||||||
|
}
|
||||||
long syscall = syscallpolicy->syscall;
|
long syscall = syscallpolicy->syscall;
|
||||||
|
|
||||||
struct sock_filter syscall_load = BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr));
|
struct sock_filter syscall_load = BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr));
|
||||||
@ -1141,7 +1150,7 @@ static struct sock_filter *append_syscall_to_bpf(struct exile_syscall_policy *sy
|
|||||||
|
|
||||||
static int is_valid_syscall_policy(unsigned int policy)
|
static int is_valid_syscall_policy(unsigned int policy)
|
||||||
{
|
{
|
||||||
return policy == EXILE_SYSCALL_ALLOW || policy == EXILE_SYSCALL_DENY_RET_ERROR || policy == EXILE_SYSCALL_DENY_KILL_PROCESS;
|
return policy == EXILE_SYSCALL_ALLOW || policy == EXILE_SYSCALL_DENY_RET_ERROR || policy == EXILE_SYSCALL_DENY_KILL_PROCESS || policy == EXILE_SYSCALL_DENY_RET_NOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1406,6 +1415,11 @@ static int check_policy_sanity(struct exile_policy *policy)
|
|||||||
{
|
{
|
||||||
if(syscall_policy->syscall == EXILE_SYSCALL_MATCH_ALL)
|
if(syscall_policy->syscall == EXILE_SYSCALL_MATCH_ALL)
|
||||||
{
|
{
|
||||||
|
if(policy->vow_promises != 0)
|
||||||
|
{
|
||||||
|
EXILE_LOG_ERROR("It's not possible to specify a default, all matching syscall policy while also using vows\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
last_match_all = i;
|
last_match_all = i;
|
||||||
match_all_policy = syscall_policy->policy;
|
match_all_policy = syscall_policy->policy;
|
||||||
}
|
}
|
||||||
@ -1416,7 +1430,7 @@ static int check_policy_sanity(struct exile_policy *policy)
|
|||||||
syscall_policy = syscall_policy->next;
|
syscall_policy = syscall_policy->next;
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
if(last_match_all == -1 || i - last_match_all != 1)
|
if(policy->vow_promises == 0 && (last_match_all == -1 || i - last_match_all != 1))
|
||||||
{
|
{
|
||||||
EXILE_LOG_ERROR("The last entry in the syscall policy list must match all syscalls (default rule)\n");
|
EXILE_LOG_ERROR("The last entry in the syscall policy list must match all syscalls (default rule)\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -1437,7 +1451,20 @@ static void close_file_fds()
|
|||||||
long max_files = sysconf(_SC_OPEN_MAX);
|
long max_files = sysconf(_SC_OPEN_MAX);
|
||||||
for(long i = 3; i <= max_files; i++)
|
for(long i = 3; i <= max_files; i++)
|
||||||
{
|
{
|
||||||
close((int)i);
|
struct stat statbuf;
|
||||||
|
int fd = (int) max_files;
|
||||||
|
int result = fstat(i, &statbuf);
|
||||||
|
if(result == -1 && errno != EBADF && errno != EACCES)
|
||||||
|
{
|
||||||
|
EXILE_LOG_ERROR("Could not fstat %i: %s\n", fd, strerror(errno));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
int type = statbuf.st_mode & S_IFMT;
|
||||||
|
if(type != S_IFIFO && type != S_IFSOCK)
|
||||||
|
{
|
||||||
|
/* No error check, retrying not recommended */
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1500,6 +1527,11 @@ int exile_enable_policy(struct exile_policy *policy)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(policy->keep_fds_open != 1)
|
||||||
|
{
|
||||||
|
close_file_fds();
|
||||||
|
}
|
||||||
|
|
||||||
if(enter_namespaces(policy->namespace_options) < 0)
|
if(enter_namespaces(policy->namespace_options) < 0)
|
||||||
{
|
{
|
||||||
EXILE_LOG_ERROR("Error while trying to enter namespaces\n");
|
EXILE_LOG_ERROR("Error while trying to enter namespaces\n");
|
||||||
|
3
exile.h
3
exile.h
@ -75,6 +75,7 @@
|
|||||||
#define EXILE_UNSHARE_NETWORK 1<<1
|
#define EXILE_UNSHARE_NETWORK 1<<1
|
||||||
#define EXILE_UNSHARE_USER 1<<2
|
#define EXILE_UNSHARE_USER 1<<2
|
||||||
#define EXILE_UNSHARE_MOUNT 1<<3
|
#define EXILE_UNSHARE_MOUNT 1<<3
|
||||||
|
#define EXILE_UNSHARE_AUTOMATIC 1<<4
|
||||||
|
|
||||||
#ifndef EXILE_LOG_ERROR
|
#ifndef EXILE_LOG_ERROR
|
||||||
#define EXILE_LOG_ERROR(...) do { fprintf(stderr, "exile.h: %s(): Error: ", __func__); fprintf(stderr, __VA_ARGS__); } while(0)
|
#define EXILE_LOG_ERROR(...) do { fprintf(stderr, "exile.h: %s(): Error: ", __func__); fprintf(stderr, __VA_ARGS__); } while(0)
|
||||||
@ -273,6 +274,7 @@ struct exile_path_policy
|
|||||||
#define EXILE_SYSCALL_ALLOW 1
|
#define EXILE_SYSCALL_ALLOW 1
|
||||||
#define EXILE_SYSCALL_DENY_KILL_PROCESS 2
|
#define EXILE_SYSCALL_DENY_KILL_PROCESS 2
|
||||||
#define EXILE_SYSCALL_DENY_RET_ERROR 3
|
#define EXILE_SYSCALL_DENY_RET_ERROR 3
|
||||||
|
#define EXILE_SYSCALL_DENY_RET_NOSYS 4
|
||||||
|
|
||||||
#define EXILE_BPF_NOP \
|
#define EXILE_BPF_NOP \
|
||||||
BPF_STMT(BPF_JMP+BPF_JA,0)
|
BPF_STMT(BPF_JMP+BPF_JA,0)
|
||||||
@ -362,6 +364,7 @@ struct exile_policy
|
|||||||
int no_new_privs;
|
int no_new_privs;
|
||||||
int no_fs;
|
int no_fs;
|
||||||
int no_new_fds;
|
int no_new_fds;
|
||||||
|
int keep_fds_open;
|
||||||
int namespace_options;
|
int namespace_options;
|
||||||
int disable_syscall_filter;
|
int disable_syscall_filter;
|
||||||
/* Bind mounts all paths in path_policies into the chroot and applies
|
/* Bind mounts all paths in path_policies into the chroot and applies
|
||||||
|
19
test.c
19
test.c
@ -643,6 +643,24 @@ int test_vows_from_str()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_clone3_nosys()
|
||||||
|
{
|
||||||
|
struct exile_policy *policy = exile_init_policy();
|
||||||
|
policy->vow_promises = exile_vows_from_str("stdio rpath wpath cpath thread error");
|
||||||
|
|
||||||
|
exile_enable_policy(policy);
|
||||||
|
/* While args are invalid, it should never reach clone3 syscall handler, so it's irrelevant for
|
||||||
|
our test*/
|
||||||
|
long ret = syscall(__NR_clone3, NULL, 0);
|
||||||
|
|
||||||
|
if(ret == -1 && errno != ENOSYS)
|
||||||
|
{
|
||||||
|
LOG("clone3() was not allowed but did not return ENOSYS. It returned: %li, errno: %i\n", ret, errno);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct dispatcher
|
struct dispatcher
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
@ -670,6 +688,7 @@ struct dispatcher dispatchers[] = {
|
|||||||
{ "launch", &test_launch},
|
{ "launch", &test_launch},
|
||||||
{ "launch-get", &test_launch_get},
|
{ "launch-get", &test_launch_get},
|
||||||
{ "vow_from_str", &test_vows_from_str},
|
{ "vow_from_str", &test_vows_from_str},
|
||||||
|
{ "clone3_nosys", &test_clone3_nosys},
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
Tagairt in Eagrán Nua
Cuir bac ar úsáideoir