Salīdzināt revīzijas
74 Revīzijas
1b4c5477a5
...
next
Autors | SHA1 | Datums | |
---|---|---|---|
40d23af355 | |||
b5f83499f3 | |||
ff60ec227d | |||
e711a1d53a | |||
6628bf4fb7 | |||
3fa73b0b97 | |||
8f38dc4480 | |||
42d44b0cc1 | |||
bd3641981c | |||
bbbdfc44da | |||
2dc61828f1 | |||
cdc265cedf | |||
91858efa51 | |||
88995d214d | |||
6eb47daf84 | |||
8bf87717a5 | |||
bcaefffbe8 | |||
ed5098f2c6 | |||
ea66ef76eb | |||
66def7a28f | |||
dbf8e87440 | |||
98421fab90 | |||
70c3fef500 | |||
69829374c7 | |||
005851c645 | |||
95fa11e928 | |||
97e2025758 | |||
8cfb73568a | |||
e7a5ba7f7f | |||
e52eda186b | |||
90ed5bbae9 | |||
48b6de9036 | |||
93acb13929 | |||
9247a6636b | |||
4a3ac8e0bc | |||
ed54575b89 | |||
0caff45600 | |||
080c0e53c2 | |||
4adc13215b | |||
bf29edf213 | |||
68bfd7e66c | |||
58bc50db61 | |||
1e63fa75ef | |||
6c44c88397 | |||
3780509078 | |||
fd4dfb12f0 | |||
a9e6b3ee67 | |||
3b61e90761 | |||
0e27b19999 | |||
ff70142e04 | |||
4824c6eaa9 | |||
9048a3b4fe | |||
0b54e73ff4 | |||
b2306299d5 | |||
55b43fdaac | |||
6420ca1b40 | |||
98c76089de | |||
631980b775 | |||
0be081c55d | |||
ca0f82790c | |||
77adf09d34 | |||
bcab0377f1 | |||
b469a82eec | |||
6711b394d9 | |||
9abbc7510c | |||
029762e894 | |||
6b513f8339 | |||
d2357ac676 | |||
0b0dda0de1 | |||
7115ef8b4d | |||
15a6850023 | |||
48deab0dde | |||
ce7eb57998 | |||
3407fded04 |
20
Makefile
20
Makefile
@ -1,17 +1,27 @@
|
||||
prefix = /usr/local
|
||||
bindir = $(prefix)/bin
|
||||
CFLAGS = -std=c99 -Wall -Wextra -pedantic
|
||||
CXXFLAGS = -std=c++20 -Wall -Wextra -pedantic
|
||||
|
||||
.DEFAULT_GOAL := test
|
||||
.DEFAULT_GOAL := tests
|
||||
|
||||
|
||||
clean:
|
||||
rm -f test
|
||||
rm -f test exile.o testcpp
|
||||
|
||||
test: test.c
|
||||
$(CC) test.c -g $(CFLAGS) -o test
|
||||
|
||||
check: test
|
||||
exile.o: exile.c exile.h
|
||||
$(CC) -c exile.c -g $(CFLAGS) -o exile.o
|
||||
|
||||
test: test.c exile.h exile.o
|
||||
$(CC) test.c exile.o -g $(CFLAGS) -o test
|
||||
|
||||
testcpp: test.cpp exile.h exile.hpp exile.o
|
||||
$(CXX) test.cpp exile.o -g $(CXXFLAGS) -o testcpp
|
||||
|
||||
tests: test testcpp
|
||||
|
||||
check: tests
|
||||
./test.sh
|
||||
|
||||
.PHONY: check
|
||||
|
208
README.md
208
README.md
@ -1,52 +1,216 @@
|
||||
# exile.h
|
||||
`exile.h` is a simple header-only library that provides an interface to isolate processes on Linux. Using Seccomp and Linux Namespaces for that purpose requires some knowledge of annoying details which this library aims to abstract away as much as possible, when reasonable. Hence, the goal is to provide a convenient way for processes to restrict themselves in order to mitigate the effect of exploits. Currently, it utilizes technologies like Seccomp, Namespaces and Landlock to this end.
|
||||
`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.
|
||||
|
||||
The following section offers small examples. Then the motivation is explained in more detail.
|
||||
Proper API documentation will be maintained in other files.
|
||||
|
||||
## Quick demo
|
||||
This section quickly demonstrates the simplicity of the API. It serves as an overview to get
|
||||
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.
|
||||
|
||||
While the examples show different features separately, it is generally possible to combine those.
|
||||
|
||||
### Filesystem isolation
|
||||
```c
|
||||
#include "exile.h"
|
||||
#include <assert.h>
|
||||
int main(void)
|
||||
{
|
||||
system("echo test > /home/user/testfile");
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
exile_append_path_policies(policy, EXILE_FS_ALLOW_ALL_READ, "/home/user");
|
||||
exile_append_path_policies(policy, EXILE_FS_ALLOW_ALL_READ | EXILE_FS_ALLOW_ALL_WRITE, "/tmp");
|
||||
int ret = exile_enable_policy(policy);
|
||||
if(ret != 0)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int fd = open("/home/user/test", O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
||||
assert(fd == -1);
|
||||
fd = open("/home/user/testfile", O_RDONLY);
|
||||
//use fd
|
||||
assert(fd != -1);
|
||||
fd = open("/tmp/testfile", O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
||||
//use fd
|
||||
assert(fd != -1);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
The assert() calls won't be fired, consistent with the policy.
|
||||
|
||||
### System call policies / vows
|
||||
exile.h allows specifying which syscalls are permitted or denied. In the following example,
|
||||
'ls' is never executed, as the specified "vows" do not allow the execve() system call. The
|
||||
process will be killed.
|
||||
|
||||
```c
|
||||
#include "exile.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
policy->vow_promises = exile_vows_from_str("stdio rpath wpath cpath");
|
||||
exile_enable_policy(policy);
|
||||
printf("Trying to execute...");
|
||||
execlp("/bin/ls", "ls", "/", NULL);
|
||||
}
|
||||
```
|
||||
|
||||
### Isolation from network
|
||||
exile offers a quick way to isolate a process from the default network namespace.
|
||||
|
||||
```c
|
||||
#include "exile.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
policy->namespace_options |= EXILE_UNSHARE_NETWORK;
|
||||
int ret = exile_enable_policy(policy);
|
||||
if(ret != 0)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
system("curl -I https://evil.tld");
|
||||
}
|
||||
```
|
||||
Produces ```curl: (6) Could not resolve host: evil.tld```. For example, this is useful for subprocesses which do not need
|
||||
network access, but perform tasks such as parsing user-supplied file formats.
|
||||
|
||||
### Isolation of single functions
|
||||
Currently, work is being done that hopefully will allow isolation of individual function calls in a mostly pain-free manner.
|
||||
|
||||
Consider the following C++ code:
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "exile.hpp"
|
||||
std::string cat(std::string path)
|
||||
{
|
||||
std::fstream f1;
|
||||
f1.open(path.c_str(), std::ios::in);
|
||||
std::string content;
|
||||
std::string line;
|
||||
while(getline(f1, line)) {
|
||||
content += line + "\n";
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
policy->vow_promises = exile_vows_from_str("stdio rpath");
|
||||
|
||||
std::string content = exile_launch<std::string>(policy, cat, "/etc/hosts");
|
||||
std::cout << content;
|
||||
|
||||
policy = exile_init_policy();
|
||||
policy->vow_promises = exile_vows_from_str("stdio");
|
||||
|
||||
try
|
||||
{
|
||||
content = exile_launch<std::string>(policy, cat, "/etc/hosts");
|
||||
std::cout << content;
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
std::cout << "launch failure: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We execute "cat()". The first call succeeds. In the second, we get an exception, because
|
||||
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
|
||||
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
|
||||
that clone()ing from threads opens a can of worms, particularly with locks. Hence, exile_launch()
|
||||
is best avoided in multi-threaded contexts.
|
||||
|
||||
## Status
|
||||
No release yet, expiremental, 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 according to 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
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Abstracting those details may help developers bring sandboxing into their applications.
|
||||
|
||||
## Features
|
||||
- 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
|
||||
- Dropping privileges in general, such as capabilities
|
||||
- Isolating the application from the network, etc. through Namespaces
|
||||
- Helpers to isolate single functions
|
||||
|
||||
- Systemcall filtering (using seccomp-bpf)
|
||||
- restricting file system access (using Landlock and/or Namespaces)
|
||||
- dropping privileges
|
||||
- isolating the application from the network, etc.
|
||||
|
||||
## What it's not
|
||||
A way for end users/administrators to restrict processes. In the future, a wrapper binary may be available to achieve this, but it generally aims for developers to bring sandboxing/isolation into their software. This allows a more fine-grained approach, as the developers are more familiar with their software. Applying restrictions with solutions like AppArmor requires
|
||||
them to be present and installed on the system and it's easy to break things this way.
|
||||
|
||||
Therefore, software should ideally be written with sandboxing in mind from the beginning.
|
||||
|
||||
|
||||
## Documentation
|
||||
Will be available once the interface stabilizes.
|
||||
|
||||
It's recommended to start with [README.usage.md] to get a feeling for exile.h.
|
||||
API-Documentation: [README.api.md]
|
||||
|
||||
## Limitations
|
||||
TODO:
|
||||
- seccomp must be kept up to date syscalls kernel
|
||||
- ioctl does not know the fd, so checking values is kind of strange
|
||||
- redundancies: some things are handled by capabilties, other by seccomp or both
|
||||
- seccomp no deep argument inspection
|
||||
- landlock: stat() does not apply
|
||||
- no magic, be reasonable, devs should not get sloppy, restrict IPC.
|
||||
|
||||
## Requirements
|
||||
|
||||
Kernel >=3.17
|
||||
|
||||
``sys/capabilities.h`` header. Depending on your distribution, libcap
|
||||
might be needed for this.
|
||||
|
||||
While mostly transparent to users of this API, kernel >= 5.13 is required to take advantage of Landlock.
|
||||
|
||||
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
|
||||
|
||||
|
||||
### Does the process need to be priviliged to utilize the library?
|
||||
### Does the process need to be privileged to utilize the library?
|
||||
|
||||
No.
|
||||
No.
|
||||
|
||||
### It doesn't work on Debian!
|
||||
|
||||
You can thank a Debian-specific kernel patch for that. In the future,
|
||||
the library may check against that. Execute
|
||||
### It doesn't work on my Debian version!
|
||||
You can thank a Debian-specific kernel patch for that. Execute
|
||||
`echo 1 > /proc/sys/kernel/unprivileged_userns_clone` to disable that patch for now.
|
||||
|
||||
### Examples
|
||||
- looqs: https://gitea.quitesimple.org/crtxcr/looqs
|
||||
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
|
||||
- looqs: https://github.com/quitesimpleorg/looqs
|
||||
- qswiki: https://gitea.quitesimple.org/crtxcr/qswiki
|
||||
|
||||
Outdated:
|
||||
- cgit sandboxed: https://gitea.quitesimple.org/crtxcr/cgitsb
|
||||
- qpdfviewsb sandboxed (quick and dirty): https://gitea.quitesimple.org/crtxcr/qpdfviewsb
|
||||
|
||||
### Other projects
|
||||
- [sandbox2](https://developers.google.com/code-sandboxing/sandbox2/)
|
||||
|
||||
|
||||
### Contributing
|
||||
|
||||
Contributions are very welcome. Options:
|
||||
Contributions are very welcome. Options:
|
||||
|
||||
1. Pull-Request on [github](https://github.com/quitesimpleorg/exile.h)
|
||||
2. Mail to `exile at quitesimple.org` with instructions on where to pull the changes from.
|
||||
|
1892
exile.c
Parasts fails
1892
exile.c
Parasts fails
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Ielādēt izmaiņas
1637
exile.h
1637
exile.h
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Ielādēt izmaiņas
201
exile.hpp
Parasts fails
201
exile.hpp
Parasts fails
@ -0,0 +1,201 @@
|
||||
#include "exile.h"
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifndef EXILE_MMAP_SIZE
|
||||
#define EXILE_MMAP_SIZE 128 * 1024 * 1024 //128MB
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T, typename U, typename ... Args>
|
||||
class launch_arg
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
static_assert(!std::is_pointer_v<T>);
|
||||
|
||||
public:
|
||||
struct exile_policy *policy;
|
||||
T *result_shm;
|
||||
U fn;
|
||||
std::tuple<Args...> args;
|
||||
|
||||
launch_arg(struct exile_policy *policy, T *result_shm, U fn, Args && ... args) : policy(policy),
|
||||
result_shm(result_shm), fn(fn), args(std::forward<Args>(args)...) {}
|
||||
|
||||
};
|
||||
|
||||
template<typename T, typename U, typename ... Args>
|
||||
class launch_arg_serializer
|
||||
{
|
||||
static_assert(std::is_copy_constructible_v<T>);
|
||||
|
||||
public:
|
||||
struct exile_policy *policy;
|
||||
char *serialize_buffer;
|
||||
size_t n;
|
||||
U fn;
|
||||
std::tuple<Args...> args;
|
||||
|
||||
const std::function<size_t (const T &, char *, size_t n)> &serializer;
|
||||
const std::function<T(const char * buf, size_t n)> &deserializer;
|
||||
|
||||
launch_arg_serializer(struct exile_policy *policy, char *serialize_buffer, size_t n, const std::function<size_t (const T &, char *, size_t)> &serializer, const std::function<T(const char *, size_t)> &deserializer, U fn, Args && ... args) : policy(policy), serialize_buffer(serialize_buffer), n(n), fn(fn), args(std::forward<Args>(args)...), serializer(serializer), deserializer(deserializer) {}
|
||||
};
|
||||
|
||||
template<typename T, typename U, typename ... Args>
|
||||
int exile_clone_handle_trivial(void * arg)
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
static_assert(!std::is_pointer_v<T>);
|
||||
|
||||
launch_arg<T, U, Args...> *launchargs = (launch_arg<T, U, Args...> *) arg;
|
||||
int ret = exile_enable_policy(launchargs->policy);
|
||||
if(ret != 0)
|
||||
{
|
||||
EXILE_LOG_ERROR("exile_enable_policy() failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
T result = std::apply(launchargs->fn, launchargs->args);
|
||||
std::cout << result;
|
||||
memcpy(launchargs->result_shm, &result, sizeof(T));
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename U, typename ... Args>
|
||||
int exile_clone_handle_serializer(void * arg)
|
||||
{
|
||||
static_assert(std::is_copy_constructible_v<T>);
|
||||
|
||||
launch_arg_serializer<T, U, Args...> *launchargs = (launch_arg_serializer<T, U, Args...> *) arg;
|
||||
int ret = exile_enable_policy(launchargs->policy);
|
||||
if(ret != 0)
|
||||
{
|
||||
EXILE_LOG_ERROR("exile_enable_policy() failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
T result = std::apply(launchargs->fn, launchargs->args);
|
||||
/* TODO: exception handling */
|
||||
/* TODO: ugly :S */
|
||||
char *target = launchargs->serialize_buffer + sizeof(size_t);
|
||||
size_t n = launchargs->n - sizeof(size_t);
|
||||
|
||||
size_t size = launchargs->serializer(result, target, n);
|
||||
memcpy(launchargs->serialize_buffer, &size, sizeof(size_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int do_clone(int (*clonefn)(void *), void *launcharg)
|
||||
{
|
||||
struct rlimit rlimit;
|
||||
int ret = getrlimit(RLIMIT_STACK, &rlimit);
|
||||
if(ret != 0)
|
||||
{
|
||||
EXILE_LOG_ERROR("Failed to get stack size: %s\n", strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
size_t size = rlimit.rlim_cur;
|
||||
char *stack = (char *) calloc(1, size);
|
||||
char *stackbegin = stack;
|
||||
if(stack == NULL)
|
||||
{
|
||||
EXILE_LOG_ERROR("Failed to allocate stack memory for child\n");
|
||||
return 1;
|
||||
}
|
||||
stack += size;
|
||||
|
||||
ret = clone(clonefn, stack, 17 /* SIGCHLD */, launcharg);
|
||||
int status = 0;
|
||||
waitpid(ret, &status, __WALL);
|
||||
free(stackbegin);
|
||||
if(WIFEXITED(status))
|
||||
{
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
/* TODO: exception or what? */
|
||||
return 23;
|
||||
}
|
||||
|
||||
template<typename T, typename U, typename ... Args>
|
||||
typename std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T> exile_launch(struct exile_policy *policy, U fn, Args && ... args)
|
||||
{
|
||||
size_t mapsize = sizeof(T);
|
||||
T * sharedbuf = (T *) mmap(NULL, mapsize , PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if(sharedbuf == NULL)
|
||||
{
|
||||
throw std::runtime_error(std::string("mmap failed: ") + strerror(errno));
|
||||
}
|
||||
|
||||
std::shared_ptr<void> deleter(nullptr, [sharedbuf, mapsize](...){ munmap(sharedbuf, mapsize); });
|
||||
launch_arg<T, U, Args...> launcharg(policy, sharedbuf, fn, std::forward<Args>(args)...);
|
||||
|
||||
int (*clonefn)(void *) = &exile_clone_handle_trivial<T, U, Args...>;
|
||||
/* TODO: exception or what? */
|
||||
int ret = do_clone(clonefn, &launcharg);
|
||||
if(ret == 0)
|
||||
{
|
||||
return *sharedbuf;
|
||||
}
|
||||
throw std::runtime_error(std::string("clone() failed: " + std::to_string(ret)));
|
||||
return T();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T, typename U, typename ... Args>
|
||||
typename std::enable_if_t<std::is_pointer_v<T> || (!std::is_trivially_copyable_v<T> && std::is_copy_constructible_v<T>), T>
|
||||
exile_launch(struct exile_policy *policy, const std::function<size_t (const T &, char *, size_t)> &serializer, const std::function<T(const char *, size_t)> &deserializer, U fn, Args && ... args)
|
||||
{
|
||||
size_t mapsize = EXILE_MMAP_SIZE;
|
||||
char *sharedbuf = (char *) mmap(NULL, mapsize , PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if(sharedbuf == NULL)
|
||||
{
|
||||
throw std::runtime_error(std::string("mmap failed: ") + strerror(errno));
|
||||
}
|
||||
std::shared_ptr<void> deleter(nullptr, [sharedbuf, mapsize](...){ munmap(sharedbuf, mapsize); });
|
||||
|
||||
|
||||
launch_arg_serializer<T, U, Args...> launcharg(policy, sharedbuf, mapsize, serializer, deserializer, fn, std::forward<Args>(args)...);
|
||||
|
||||
int (*clonefn)(void *) = &exile_clone_handle_serializer<T, U, Args...>;
|
||||
/* TODO: exception or what? */
|
||||
int ret = do_clone(clonefn, &launcharg);
|
||||
if(ret == 0)
|
||||
{
|
||||
size_t size = 0;
|
||||
memcpy(&size, sharedbuf, sizeof(size));
|
||||
|
||||
return deserializer(sharedbuf + sizeof(size_t), size);
|
||||
}
|
||||
throw std::runtime_error(std::string("clone() failed: " + std::to_string(ret)));
|
||||
return T();
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::basic_string<typename T::value_type> deserialize_stdstring(const char *buf, size_t n)
|
||||
{
|
||||
return std::basic_string<typename T::value_type> { buf, n };
|
||||
}
|
||||
|
||||
template<class T>
|
||||
size_t serialize_stdstring(const std::basic_string<typename T::value_type> &t, char *buf, size_t n)
|
||||
{
|
||||
if(n < t.size())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
memcpy(buf, t.data(), t.size());
|
||||
return t.size();
|
||||
}
|
||||
|
||||
|
||||
template<typename T, typename U, typename ... Args>
|
||||
std::basic_string<typename T::value_type> exile_launch(struct exile_policy *policy, U fn, Args && ... args)
|
||||
{
|
||||
return exile_launch<T, U, Args...>(policy, &serialize_stdstring<T>, &deserialize_stdstring<T>, fn, std::forward<Args>(args) ...);
|
||||
}
|
55
gengroup.py
55
gengroup.py
@ -1,55 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import re
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: gengroup groupfile")
|
||||
sys.exit(1)
|
||||
fd = open(sys.argv[1], "r")
|
||||
|
||||
lines = fd.read().splitlines()
|
||||
|
||||
groupnames = set()
|
||||
ifndef = dict()
|
||||
|
||||
def print_ifndefs():
|
||||
for name in ifndef:
|
||||
print("#ifndef __NR_%s" % name)
|
||||
print("#define __NR_%s %s" % (name, ifndef[name]))
|
||||
print("#endif")
|
||||
|
||||
def print_defines(names):
|
||||
names = sorted(names)
|
||||
i = 0
|
||||
for name in names:
|
||||
define = "#define %s ((uint64_t)1<<%s)" % (name, i)
|
||||
print(define)
|
||||
i = i + 1
|
||||
|
||||
for line in lines:
|
||||
if line[0] == '#':
|
||||
continue
|
||||
|
||||
splitted = line.split(' ')
|
||||
if len(splitted) < 2:
|
||||
print("Misformated line:", line)
|
||||
sys.exit(1)
|
||||
|
||||
currentsyscall = splitted[0]
|
||||
currentgroups = splitted[1].split(',')
|
||||
|
||||
flags = splitted[2] if len(splitted) > 2 else ""
|
||||
if any( not s or s.isspace() for s in currentgroups ):
|
||||
print("Misformated line (empty values):", line)
|
||||
sys.exit(1)
|
||||
groupnames.update(currentgroups)
|
||||
|
||||
genifndef = re.match(r"genifndef\((\d+)*\)", flags)
|
||||
if genifndef:
|
||||
ifndef[currentsyscall] = genifndef.groups(1)[0]
|
||||
|
||||
array_line = "{EXILE_SYS(%s), %s}," % (currentsyscall, '|'.join(currentgroups))
|
||||
print(array_line)
|
||||
|
||||
print_ifndefs()
|
||||
print_defines(groupnames)
|
||||
|
@ -1,363 +0,0 @@
|
||||
# Assign system calls to groups. In the future, may also include simple arg filtering.
|
||||
read EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
write EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
open EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
close EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
stat EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
fstat EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
lstat EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
poll EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
lseek EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
mmap EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
mprotect EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
munmap EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
brk EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
rt_sigaction EXILE_SYSCGROUP_RT,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
rt_sigprocmask EXILE_SYSCGROUP_RT,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
rt_sigreturn EXILE_SYSCGROUP_RT,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
ioctl EXILE_SYSCGROUP_IOCTL,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
pread64 EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
pwrite64 EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
readv EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
writev EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
access EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
pipe EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
select EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
sched_yield EXILE_SYSCGROUP_SCHED,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
mremap EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
msync EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
mincore EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
madvise EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
shmget EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
shmat EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
shmctl EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
dup EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
dup2 EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
pause EXILE_SYSCGROUP_PAUSE,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
nanosleep EXILE_SYSCGROUP_TIMER,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
getitimer EXILE_SYSCGROUP_TIMER,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
alarm EXILE_SYSCGROUP_TIMER,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
setitimer EXILE_SYSCGROUP_TIMER,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
getpid EXILE_SYSCGROUP_PROCESS,EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
sendfile EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
socket EXILE_SYSCGROUP_SOCKET
|
||||
connect EXILE_SYSCGROUP_SOCKET
|
||||
accept EXILE_SYSCGROUP_SOCKET
|
||||
sendto EXILE_SYSCGROUP_SOCKET
|
||||
recvfrom EXILE_SYSCGROUP_SOCKET
|
||||
sendmsg EXILE_SYSCGROUP_SOCKET
|
||||
recvmsg EXILE_SYSCGROUP_SOCKET
|
||||
shutdown EXILE_SYSCGROUP_SOCKET
|
||||
bind EXILE_SYSCGROUP_SOCKET
|
||||
listen EXILE_SYSCGROUP_SOCKET
|
||||
getsockname EXILE_SYSCGROUP_SOCKET
|
||||
getpeername EXILE_SYSCGROUP_SOCKET
|
||||
socketpair EXILE_SYSCGROUP_SOCKET,EXILE_SYSCGROUP_IPC
|
||||
setsockopt EXILE_SYSCGROUP_SOCKET
|
||||
getsockopt EXILE_SYSCGROUP_SOCKET
|
||||
clone EXILE_SYSCGROUP_CLONE,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
fork EXILE_SYSCGROUP_CLONE,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
vfork EXILE_SYSCGROUP_CLONE,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
execve EXILE_SYSCGROUP_CLONE,EXILE_SYSCGROUP_EXEC
|
||||
exit EXILE_SYSCGROUP_PROCESS,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
wait4 EXILE_SYSCGROUP_EXEC
|
||||
kill EXILE_SYSCGROUP_KILL
|
||||
uname EXILE_SYSCGROUP_SYS,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
semget EXILE_SYSCGROUP_SHM,EXILE_SYSCGROUP_IPC,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
semop EXILE_SYSCGROUP_SHM,EXILE_SYSCGROUP_IPC,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
semctl EXILE_SYSCGROUP_SHM,EXILE_SYSCGROUP_IPC,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
shmdt EXILE_SYSCGROUP_SHM,EXILE_SYSCGROUP_IPC,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
msgget EXILE_SYSCGROUP_IPC,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
msgsnd EXILE_SYSCGROUP_IPC,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
msgrcv EXILE_SYSCGROUP_IPC,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
msgctl EXILE_SYSCGROUP_IPC,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
fcntl EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
flock EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
fsync EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
fdatasync EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
truncate EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
ftruncate EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
getdents EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
getcwd EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
chdir EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
fchdir EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
rename EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
mkdir EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
rmdir EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
creat EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
link EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
unlink EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
symlink EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
readlink EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
chmod EXILE_SYSCGROUP_PERMS,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
fchmod EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
chown EXILE_SYSCGROUP_PERMS,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
fchown EXILE_SYSCGROUP_PERMS,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
lchown EXILE_SYSCGROUP_PERMS,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
umask EXILE_SYSCGROUP_PERMS,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
gettimeofday EXILE_SYSCGROUP_TIME,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
getrlimit EXILE_SYSCGROUP_RES,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
getrusage EXILE_SYSCGROUP_RES,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
sysinfo EXILE_SYSCGROUP_SYS,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
times EXILE_SYSCGROUP_TIME,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
ptrace EXILE_SYSCGROUP_PTRACE,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
getuid EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
syslog EXILE_SYSCGROUP_SYS
|
||||
getgid EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
setuid EXILE_SYSCGROUP_ID
|
||||
setgid EXILE_SYSCGROUP_ID
|
||||
geteuid EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
getegid EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
setpgid EXILE_SYSCGROUP_ID
|
||||
getppid EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
getpgrp EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
setsid EXILE_SYSCGROUP_ID
|
||||
setreuid EXILE_SYSCGROUP_ID
|
||||
setregid EXILE_SYSCGROUP_ID
|
||||
getgroups EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
setgroups EXILE_SYSCGROUP_ID
|
||||
setresuid EXILE_SYSCGROUP_ID
|
||||
getresuid EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
setresgid EXILE_SYSCGROUP_ID
|
||||
getresgid EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
getpgid EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
setfsuid EXILE_SYSCGROUP_ID
|
||||
setfsgid EXILE_SYSCGROUP_ID
|
||||
getsid EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
capget EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
capset EXILE_SYSCGROUP_ID
|
||||
rt_sigpending EXILE_SYSCGROUP_RT,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
rt_sigtimedwait EXILE_SYSCGROUP_RT,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
rt_sigqueueinfo EXILE_SYSCGROUP_RT,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
rt_sigsuspend EXILE_SYSCGROUP_RT,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
sigaltstack EXILE_SYSCGROUP_THREAD,EXILE_SYSCGROUP_SIGNAL
|
||||
utime EXILE_SYSCGROUP_TIME,EXILE_SYSCGROUP_FS
|
||||
mknod EXILE_SYSCGROUP_DEV,EXILE_SYSCGROUP_FS
|
||||
uselib EXILE_SYSCGROUP_LIB,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
personality EXILE_SYSCGROUP_PROCESS
|
||||
ustat EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_STAT,EXILE_SYSCGROUP_FS
|
||||
statfs EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_STAT,EXILE_SYSCGROUP_FS
|
||||
fstatfs EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_STAT,EXILE_SYSCGROUP_FS
|
||||
sysfs EXILE_SYSCGROUP_SYS,EXILE_SYSCGROUP_FS
|
||||
getpriority EXILE_SYSCGROUP_SCHED
|
||||
setpriority EXILE_SYSCGROUP_SCHED
|
||||
sched_setparam EXILE_SYSCGROUP_SCHED
|
||||
sched_getparam EXILE_SYSCGROUP_SCHED
|
||||
sched_setscheduler EXILE_SYSCGROUP_SCHED
|
||||
sched_getscheduler EXILE_SYSCGROUP_SCHED
|
||||
sched_get_priority_max EXILE_SYSCGROUP_SCHED
|
||||
sched_get_priority_min EXILE_SYSCGROUP_SCHED
|
||||
sched_rr_get_interval EXILE_SYSCGROUP_SCHED
|
||||
mlock EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
munlock EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
mlockall EXILE_SYSCGROUP_MEMORY
|
||||
munlockall EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
vhangup EXILE_SYSCGROUP_TTY
|
||||
modify_ldt EXILE_SYSCGROUP_PROCESS
|
||||
pivot_root EXILE_SYSCGROUP_CHROOT
|
||||
_sysctl EXILE_SYSCGROUP_SYS
|
||||
prctl EXILE_SYSCGROUP_PROCESS
|
||||
arch_prctl EXILE_SYSCGROUP_PROCESS
|
||||
adjtimex EXILE_SYSCGROUP_CLOCK
|
||||
setrlimit EXILE_SYSCGROUP_RES
|
||||
chroot EXILE_SYSCGROUP_CHROOT,EXILE_SYSCGROUP_FS
|
||||
sync EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
acct EXILE_SYSCGROUP_PROCESS
|
||||
settimeofday EXILE_SYSCGROUP_TIME
|
||||
mount EXILE_SYSCGROUP_MOUNT,EXILE_SYSCGROUP_FS
|
||||
umount2 EXILE_SYSCGROUP_UMOUNT,EXILE_SYSCGROUP_FS
|
||||
swapon EXILE_SYSCGROUP_SWAP
|
||||
swapoff EXILE_SYSCGROUP_SWAP
|
||||
reboot EXILE_SYSCGROUP_POWER
|
||||
sethostname EXILE_SYSCGROUP_HOST
|
||||
setdomainname EXILE_SYSCGROUP_HOST
|
||||
iopl EXILE_SYSCGROUP_IOPL
|
||||
ioperm EXILE_SYSCGROUP_IOPL
|
||||
create_module EXILE_SYSCGROUP_KMOD
|
||||
init_module EXILE_SYSCGROUP_KMOD
|
||||
delete_module EXILE_SYSCGROUP_KMOD
|
||||
get_kernel_syms EXILE_SYSCGROUP_KMOD
|
||||
query_module EXILE_SYSCGROUP_KMOD
|
||||
quotactl EXILE_SYSCGROUP_QUOTA
|
||||
nfsservctl EXILE_SYSCGROUP_NONE
|
||||
getpmsg EXILE_SYSCGROUP_UNIMPLEMENTED
|
||||
putpmsg EXILE_SYSCGROUP_UNIMPLEMENTED
|
||||
afs_syscall EXILE_SYSCGROUP_UNIMPLEMENTED
|
||||
tuxcall EXILE_SYSCGROUP_UNIMPLEMENTED
|
||||
security EXILE_SYSCGROUP_UNIMPLEMENTED
|
||||
gettid EXILE_SYSCGROUP_ID,EXILE_SYSCGROUP_THREAD
|
||||
readahead EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_FS
|
||||
setxattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_FS
|
||||
lsetxattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_FS
|
||||
fsetxattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_FS
|
||||
getxattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
lgetxattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
fgetxattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
listxattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_FS
|
||||
llistxattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_FS
|
||||
flistxattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_FS
|
||||
removexattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_FS
|
||||
lremovexattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_FS
|
||||
fremovexattr EXILE_SYSCGROUP_XATTR,EXILE_SYSCGROUP_FS
|
||||
tkill EXILE_SYSCGROUP_THREAD,EXILE_SYSCGROUP_SIGNAL
|
||||
time EXILE_SYSCGROUP_TIME
|
||||
futex EXILE_SYSCGROUP_THREAD,EXILE_SYSCGROUP_FUTEX
|
||||
sched_setaffinity EXILE_SYSCGROUP_SCHED
|
||||
sched_getaffinity EXILE_SYSCGROUP_SCHED
|
||||
set_thread_area EXILE_SYSCGROUP_THREAD
|
||||
io_setup EXILE_SYSCGROUP_IO
|
||||
io_destroy EXILE_SYSCGROUP_IO
|
||||
io_getevents EXILE_SYSCGROUP_IO
|
||||
io_submit EXILE_SYSCGROUP_IO
|
||||
io_cancel EXILE_SYSCGROUP_IO
|
||||
get_thread_area EXILE_SYSCGROUP_THREAD
|
||||
lookup_dcookie EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_FS
|
||||
epoll_create EXILE_SYSCGROUP_STDIO
|
||||
epoll_ctl_old EXILE_SYSCGROUP_STDIO
|
||||
epoll_wait_old EXILE_SYSCGROUP_STDIO
|
||||
remap_file_pages EXILE_SYSCGROUP_NONE
|
||||
getdents64 EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_FS
|
||||
set_tid_address EXILE_SYSCGROUP_THREAD
|
||||
restart_syscall EXILE_SYSCGROUP_SYSCALL
|
||||
semtimedop EXILE_SYSCGROUP_SEM
|
||||
fadvise64 EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_FD
|
||||
timer_create EXILE_SYSCGROUP_TIMER
|
||||
timer_settime EXILE_SYSCGROUP_TIMER
|
||||
timer_gettime EXILE_SYSCGROUP_TIMER
|
||||
timer_getoverrun EXILE_SYSCGROUP_TIMER
|
||||
timer_delete EXILE_SYSCGROUP_TIMER
|
||||
clock_settime EXILE_SYSCGROUP_TIME
|
||||
clock_gettime EXILE_SYSCGROUP_TIME
|
||||
clock_getres EXILE_SYSCGROUP_TIME
|
||||
clock_nanosleep EXILE_SYSCGROUP_TIME
|
||||
exit_group EXILE_SYSCGROUP_EXIT,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
epoll_wait EXILE_SYSCGROUP_FD
|
||||
epoll_ctl EXILE_SYSCGROUP_FD
|
||||
tgkill EXILE_SYSCGROUP_SIGNAL,EXILE_SYSCGROUP_THREAD
|
||||
utimes EXILE_SYSCGROUP_PATH
|
||||
vserver EXILE_SYSCGROUP_UNIMPLEMENTED
|
||||
mbind EXILE_SYSCGROUP_MEMORY
|
||||
set_mempolicy EXILE_SYSCGROUP_MEMORY
|
||||
get_mempolicy EXILE_SYSCGROUP_MEMORY
|
||||
mq_open EXILE_SYSCGROUP_MQ,EXILE_SYSCGROUP_IPC
|
||||
mq_unlink EXILE_SYSCGROUP_MQ,EXILE_SYSCGROUP_IPC
|
||||
mq_timedsend EXILE_SYSCGROUP_MQ,EXILE_SYSCGROUP_IPC
|
||||
mq_timedreceive EXILE_SYSCGROUP_MQ,EXILE_SYSCGROUP_IPC
|
||||
mq_notify EXILE_SYSCGROUP_MQ,EXILE_SYSCGROUP_IPC
|
||||
mq_getsetattr EXILE_SYSCGROUP_MQ,EXILE_SYSCGROUP_IPC
|
||||
kexec_load EXILE_SYSCGROUP_KEXEC
|
||||
waitid EXILE_SYSCGROUP_SIGNAL
|
||||
add_key EXILE_SYSCGROUP_KEYS
|
||||
request_key EXILE_SYSCGROUP_KEYS
|
||||
keyctl EXILE_SYSCGROUP_KEYS
|
||||
ioprio_set EXILE_SYSCGROUP_PRIO
|
||||
ioprio_get EXILE_SYSCGROUP_PRIO
|
||||
inotify_init EXILE_SYSCGROUP_INOTIFY
|
||||
inotify_add_watch EXILE_SYSCGROUP_INOTIFY
|
||||
inotify_rm_watch EXILE_SYSCGROUP_INOTIFY
|
||||
migrate_pages EXILE_SYSCGROUP_PROCESS
|
||||
openat EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
mkdirat EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
mknodat EXILE_SYSCGROUP_DEV,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
fchownat EXILE_SYSCGROUP_PERMS,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
futimesat EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
newfstatat EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
unlinkat EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
renameat EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
linkat EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
symlinkat EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
readlinkat EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
fchmodat EXILE_SYSCGROUP_PERMS,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
faccessat EXILE_SYSCGROUP_PERMS,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
pselect6 EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
ppoll EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW,EXILE_SYSCGROUP_FS
|
||||
unshare EXILE_SYSCGROUP_NS,EXILE_SYSCGROUP_FS
|
||||
set_robust_list EXILE_SYSCGROUP_FUTEX
|
||||
get_robust_list EXILE_SYSCGROUP_FUTEX
|
||||
splice EXILE_SYSCGROUP_FD
|
||||
tee EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
sync_file_range EXILE_SYSCGROUP_FD
|
||||
vmsplice EXILE_SYSCGROUP_FD
|
||||
move_pages EXILE_SYSCGROUP_PROCESS
|
||||
utimensat EXILE_SYSCGROUP_PATH
|
||||
epoll_pwait EXILE_SYSCGROUP_STDIO
|
||||
signalfd EXILE_SYSCGROUP_SIGNAL
|
||||
timerfd_create EXILE_SYSCGROUP_TIMER
|
||||
eventfd EXILE_SYSCGROUP_FD
|
||||
fallocate EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_FD
|
||||
timerfd_settime EXILE_SYSCGROUP_TIMER
|
||||
timerfd_gettime EXILE_SYSCGROUP_TIMER
|
||||
accept4 EXILE_SYSCGROUP_SOCKET
|
||||
signalfd4 EXILE_SYSCGROUP_FD
|
||||
eventfd2 EXILE_SYSCGROUP_FD
|
||||
epoll_create1 EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
dup3 EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
pipe2 EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
inotify_init1 EXILE_SYSCGROUP_INOTIFY
|
||||
preadv EXILE_SYSCGROUP_STDIO
|
||||
pwritev EXILE_SYSCGROUP_STDIO
|
||||
rt_tgsigqueueinfo EXILE_SYSCGROUP_RT
|
||||
perf_event_open EXILE_SYSCGROUP_PERF
|
||||
recvmmsg EXILE_SYSCGROUP_SOCKET
|
||||
fanotify_init EXILE_SYSCGROUP_FANOTIFY
|
||||
fanotify_mark EXILE_SYSCGROUP_FANOTIFY
|
||||
prlimit64 EXILE_SYSCGROUP_RES
|
||||
name_to_handle_at EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_FS
|
||||
open_by_handle_at EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_FS
|
||||
clock_adjtime EXILE_SYSCGROUP_CLOCK
|
||||
syncfs EXILE_SYSCGROUP_FD
|
||||
sendmmsg EXILE_SYSCGROUP_SOCKET
|
||||
setns EXILE_SYSCGROUP_NS
|
||||
getcpu EXILE_SYSCGROUP_SCHED
|
||||
#maybe IPC, but feels wrong
|
||||
process_vm_readv EXILE_SYSCGROUP_NONE
|
||||
process_vm_writev EXILE_SYSCGROUP_NONE
|
||||
kcmp EXILE_SYSCGROUP_NONE
|
||||
finit_module EXILE_SYSCGROUP_KMOD
|
||||
sched_setattr EXILE_SYSCGROUP_SCHED
|
||||
sched_getattr EXILE_SYSCGROUP_SCHED,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
renameat2 EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
seccomp EXILE_SYSCGROUP_NONE
|
||||
getrandom EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
memfd_create EXILE_SYSCGROUP_MEMORY,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
kexec_file_load EXILE_SYSCGROUP_KEXEC
|
||||
bpf EXILE_SYSCGROUP_NONE
|
||||
execveat EXILE_SYSCGROUP_EXEC
|
||||
userfaultfd EXILE_SYSCGROUP_NONE
|
||||
membarrier EXILE_SYSCGROUP_NONE
|
||||
mlock2 EXILE_SYSCGROUP_MEMORY
|
||||
copy_file_range EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_DEFAULT_ALLOW
|
||||
preadv2 EXILE_SYSCGROUP_STDIO
|
||||
pwritev2 EXILE_SYSCGROUP_STDIO
|
||||
#Those are newer than 5.10, wrap them in ifndef so we can compile on old systems
|
||||
pkey_mprotect EXILE_SYSCGROUP_PKEY genifndef(329)
|
||||
pkey_alloc EXILE_SYSCGROUP_PKEY genifndef(330)
|
||||
pkey_free EXILE_SYSCGROUP_PKEY genifndef(331)
|
||||
statx EXILE_SYSCGROUP_STAT,EXILE_SYSCGROUP_DEFAULT_ALLOW genifndef(332)
|
||||
io_pgetevents EXILE_SYSCGROUP_NONE genifndef(333)
|
||||
rseq EXILE_SYSCGROUP_THREAD genifndef(334)
|
||||
pidfd_send_signal EXILE_SYSCGROUP_PIDFD genifndef(424)
|
||||
io_uring_setup EXILE_SYSCGROUP_IOURING genifndef(425)
|
||||
io_uring_enter EXILE_SYSCGROUP_IOURING genifndef(426)
|
||||
io_uring_register EXILE_SYSCGROUP_IOURING genifndef(427)
|
||||
open_tree EXILE_SYSCGROUP_NEWMOUNT genifndef(428)
|
||||
move_mount EXILE_SYSCGROUP_NEWMOUNT genifndef(429)
|
||||
fsopen EXILE_SYSCGROUP_NEWMOUNT genifndef(430)
|
||||
fsconfig EXILE_SYSCGROUP_NEWMOUNT genifndef(431)
|
||||
fsmount EXILE_SYSCGROUP_NEWMOUNT genifndef(432)
|
||||
fspick EXILE_SYSCGROUP_NEWMOUNT genifndef(433)
|
||||
pidfd_open EXILE_SYSCGROUP_PIDFD genifndef(434)
|
||||
clone3 EXILE_SYSCGROUP_CLONE,EXILE_SYSCGROUP_DEFAULT_ALLOW genifndef(435)
|
||||
close_range EXILE_SYSCGROUP_STDIO,EXILE_SYSCGROUP_DEFAULT_ALLOW genifndef(436)
|
||||
openat2 EXILE_SYSCGROUP_FD,EXILE_SYSCGROUP_PATH,EXILE_SYSCGROUP_DEFAULT_ALLOW genifndef(437)
|
||||
pidfd_getfd EXILE_SYSCGROUP_PIDFD genifndef(438)
|
||||
faccessat2 EXILE_SYSCGROUP_PERMS,EXILE_SYSCGROUP_DEFAULT_ALLOW genifndef(439)
|
||||
process_madvise EXILE_SYSCGROUP_MEMORY genifndef(440)
|
||||
epoll_pwait2 EXILE_SYSCGROUP_STDIO genifndef(441)
|
||||
mount_setattr EXILE_SYSCGROUP_NONE genifndef(442)
|
||||
quotactl_fd EXILE_SYSCGROUP_QUOTA genifndef(443)
|
||||
landlock_create_ruleset EXILE_SYSCGROUP_LANDLOCK genifndef(444)
|
||||
landlock_add_rule EXILE_SYSCGROUP_LANDLOCK genifndef(445)
|
||||
landlock_restrict_self EXILE_SYSCGROUP_LANDLOCK genifndef(446)
|
||||
memfd_secret EXILE_SYSCGROUP_NONE genifndef(447)
|
||||
process_mrelease EXILE_SYSCGROUP_NONE genifndef(448)
|
451
test.c
451
test.c
@ -6,12 +6,14 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define LOG(...) do { fprintf(stdout, "%s(): ", __func__); fprintf(stdout, __VA_ARGS__); } while(0)
|
||||
|
||||
int xexile_enable_policy(struct exile_policy *policy)
|
||||
{
|
||||
int ret = exile_enable_policy(policy);
|
||||
if(ret != 0)
|
||||
{
|
||||
fprintf(stderr, "exile_enable_policy() failed: %i\n", ret);
|
||||
LOG("failed: %i\n", ret);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return 0;
|
||||
@ -38,16 +40,16 @@ static int test_expected_kill(int (*f)())
|
||||
int c = WTERMSIG(status);
|
||||
if(c == SIGSYS)
|
||||
{
|
||||
printf("Got expected signal\n");
|
||||
LOG("Got expected signal\n");
|
||||
return 0;
|
||||
}
|
||||
printf("Unexpected status code: %i\n", c);
|
||||
LOG("Unexpected status code: %i\n", c);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int c = WEXITSTATUS(status);
|
||||
printf("Process was not killed, test fails. Status code of exit: %i\n", c);
|
||||
LOG("Process was not killed, test fails. Status code of exit: %i\n", c);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -67,7 +69,7 @@ static int test_successful_exit(int (*f)())
|
||||
if(WIFSIGNALED(status))
|
||||
{
|
||||
int c = WTERMSIG(status);
|
||||
printf("Received signal, which was not expected. Signal was: %i\n", c);
|
||||
LOG("Received signal, which was not expected. Signal was: %i\n", c);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
@ -75,11 +77,11 @@ static int test_successful_exit(int (*f)())
|
||||
int c = WEXITSTATUS(status);
|
||||
if(c != 0)
|
||||
{
|
||||
printf("Process failed to exit properly. Status code is: %i\n", c);
|
||||
LOG("Process failed to exit properly. Status code is: %i\n", c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
printf("Process exited sucessfully as expected");
|
||||
LOG("Process exited sucessfully as expected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -87,13 +89,13 @@ static int test_successful_exit(int (*f)())
|
||||
static int do_test_seccomp_blacklisted()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
exile_append_syscall_policy(policy, EXILE_SYSCALL_DENY_KILL_PROCESS, EXILE_SYS(getuid));
|
||||
exile_append_syscall_policy(policy,EXILE_SYS(getuid), EXILE_SYSCALL_DENY_KILL_PROCESS, NULL, 0);
|
||||
exile_append_syscall_default_policy(policy, EXILE_SYSCALL_ALLOW);
|
||||
|
||||
xexile_enable_policy(policy);
|
||||
|
||||
uid_t pid = geteuid();
|
||||
pid = getuid();
|
||||
uid_t pid = syscall(EXILE_SYS(geteuid));
|
||||
pid = syscall(EXILE_SYS(getuid));
|
||||
return 0;
|
||||
|
||||
|
||||
@ -108,12 +110,12 @@ static int do_test_seccomp_blacklisted_call_permitted()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
|
||||
exile_append_syscall_policy(policy, EXILE_SYSCALL_DENY_KILL_PROCESS, EXILE_SYS(getuid));
|
||||
exile_append_syscall_policy(policy, EXILE_SYS(getuid), EXILE_SYSCALL_DENY_KILL_PROCESS, NULL, 0);
|
||||
exile_append_syscall_default_policy(policy, EXILE_SYSCALL_ALLOW);
|
||||
|
||||
xexile_enable_policy(policy);
|
||||
//geteuid is not blacklisted, so must succeed
|
||||
uid_t pid = geteuid();
|
||||
uid_t pid = syscall(EXILE_SYS(geteuid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -127,7 +129,7 @@ static int do_test_seccomp_x32_kill()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
|
||||
exile_append_syscall_policy(policy, EXILE_SYSCALL_DENY_KILL_PROCESS, EXILE_SYS(getuid));
|
||||
exile_append_syscall_policy(policy, EXILE_SYS(getuid), EXILE_SYSCALL_DENY_KILL_PROCESS, NULL, 0);
|
||||
exile_append_syscall_default_policy(policy, EXILE_SYSCALL_ALLOW);
|
||||
|
||||
xexile_enable_policy(policy);
|
||||
@ -148,12 +150,12 @@ int test_seccomp_require_last_matchall()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
|
||||
exile_append_syscall_policy(policy, EXILE_SYSCALL_DENY_KILL_PROCESS, EXILE_SYS(getuid));
|
||||
exile_append_syscall_policy(policy, EXILE_SYS(getuid), EXILE_SYSCALL_DENY_KILL_PROCESS, NULL, 0);
|
||||
|
||||
int status = exile_enable_policy(policy);
|
||||
if(status == 0)
|
||||
{
|
||||
printf("Failed. Should not have been enabled!");
|
||||
LOG("Failed. Should not have been enabled!");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -163,14 +165,14 @@ static int do_test_seccomp_errno()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
|
||||
exile_append_syscall_policy(policy, EXILE_SYSCALL_DENY_RET_ERROR, EXILE_SYS(close));
|
||||
exile_append_syscall_policy(policy, EXILE_SYS(close),EXILE_SYSCALL_DENY_RET_ERROR, NULL, 0);
|
||||
exile_append_syscall_default_policy(policy, EXILE_SYSCALL_ALLOW);
|
||||
|
||||
xexile_enable_policy(policy);
|
||||
uid_t id = getuid();
|
||||
uid_t id = syscall(EXILE_SYS(getuid));
|
||||
|
||||
int fd = close(0);
|
||||
printf("close() return code: %i, errno: %s\n", fd, strerror(errno));
|
||||
int fd = syscall(EXILE_SYS(close), 0);
|
||||
LOG("close() return code: %i, errno: %s\n", fd, strerror(errno));
|
||||
return fd == -1 ? 0 : 1;
|
||||
}
|
||||
|
||||
@ -181,29 +183,230 @@ int test_seccomp_errno()
|
||||
return test_successful_exit(&do_test_seccomp_errno);
|
||||
}
|
||||
|
||||
static int test_seccomp_group()
|
||||
int test_seccomp_argfilter_allowed()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
|
||||
exile_append_group_syscall_policy(policy, EXILE_SYSCALL_DENY_RET_ERROR, EXILE_SYSCGROUP_SOCKET);
|
||||
exile_append_syscall_default_policy(policy, EXILE_SYSCALL_ALLOW);
|
||||
struct sock_filter argfilter[2] =
|
||||
{
|
||||
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, args[1]))),
|
||||
BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, O_WRONLY, 0, EXILE_SYSCALL_EXIT_BPF_NO_MATCH)
|
||||
};
|
||||
|
||||
exile_append_syscall_policy(policy, EXILE_SYS(open),EXILE_SYSCALL_DENY_RET_ERROR, argfilter, 2);
|
||||
exile_append_syscall_default_policy(policy, EXILE_SYSCALL_ALLOW);
|
||||
xexile_enable_policy(policy);
|
||||
|
||||
int s = socket(AF_INET,SOCK_STREAM,0);
|
||||
if(s != -1)
|
||||
|
||||
char *t = "/dev/random";
|
||||
int ret = (int) syscall(EXILE_SYS(open),t, O_RDONLY);
|
||||
|
||||
if(ret == -1)
|
||||
{
|
||||
printf("Failed: socket was expected to return error\n");
|
||||
printf("Failed: open was expected to succeed, but returned %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_seccomp_argfilter_filtered()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
|
||||
struct sock_filter argfilter[2] =
|
||||
{
|
||||
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, args[1]))),
|
||||
BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, O_WRONLY, 0, EXILE_SYSCALL_EXIT_BPF_NO_MATCH)
|
||||
};
|
||||
|
||||
exile_append_syscall_policy(policy, EXILE_SYS(open),EXILE_SYSCALL_DENY_RET_ERROR, argfilter, 2);
|
||||
exile_append_syscall_default_policy(policy, EXILE_SYSCALL_ALLOW);
|
||||
xexile_enable_policy(policy);
|
||||
|
||||
char *t = "/dev/random";
|
||||
int ret = (int) syscall(EXILE_SYS(open),t, O_WRONLY);
|
||||
|
||||
if(ret != -1)
|
||||
{
|
||||
printf("Failed: open was expected to fail, but returned %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int test_seccomp_argfilter_mixed()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
|
||||
struct sock_filter argfilter[2] =
|
||||
{
|
||||
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, args[1]))),
|
||||
BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, O_WRONLY, 0, EXILE_SYSCALL_EXIT_BPF_NO_MATCH)
|
||||
};
|
||||
|
||||
exile_append_syscall_policy(policy, EXILE_SYS(stat),EXILE_SYSCALL_DENY_RET_ERROR, NULL,0);
|
||||
exile_append_syscall_policy(policy, EXILE_SYS(open),EXILE_SYSCALL_DENY_RET_ERROR, argfilter, 2);
|
||||
exile_append_syscall_policy(policy, EXILE_SYS(getpid),EXILE_SYSCALL_DENY_RET_ERROR, NULL, 0);
|
||||
|
||||
exile_append_syscall_default_policy(policy, EXILE_SYSCALL_ALLOW);
|
||||
xexile_enable_policy(policy);
|
||||
|
||||
struct stat statbuf;
|
||||
int s = (int) syscall(EXILE_SYS(stat), "/dev/urandom", &statbuf);
|
||||
if(s != -1)
|
||||
{
|
||||
LOG("Failed: stat was expected to fail, but returned %i\n", s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid_t p = (pid_t) syscall(EXILE_SYS(getpid));
|
||||
if(p != -1)
|
||||
{
|
||||
LOG("Failed: getpid was expected to fail, but returned %i\n", p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *t = "/dev/random";
|
||||
int ret = (int) syscall(EXILE_SYS(open),t, O_WRONLY);
|
||||
if(ret != -1)
|
||||
{
|
||||
LOG("Failed: open was expected to fail, but returned %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
ret = (int) syscall(EXILE_SYS(open), t, O_RDONLY);
|
||||
if(ret == -1)
|
||||
{
|
||||
LOG("Failed: open with O_RDONLY was expected to succeed, but returned %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int do_test_seccomp_vow_socket()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
policy->vow_promises = EXILE_SYSCALL_VOW_STDIO | EXILE_SYSCALL_VOW_INET | EXILE_SYSCALL_VOW_DENY_ERROR;
|
||||
xexile_enable_policy(policy);
|
||||
|
||||
int s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(s == -1)
|
||||
{
|
||||
LOG("Failed: socket was expected to succeed, but returned %i\n", s);
|
||||
return 1;
|
||||
}
|
||||
s = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if(s != -1)
|
||||
{
|
||||
LOG("Failed: socket was expected to fail, but returned %i\n", s);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_test_seccomp_vow_open()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
policy->vow_promises = EXILE_SYSCALL_VOW_STDIO | EXILE_SYSCALL_VOW_RPATH | EXILE_SYSCALL_VOW_DENY_ERROR;
|
||||
xexile_enable_policy(policy);
|
||||
|
||||
int ret = open("/dev/urandom", O_WRONLY | O_APPEND);
|
||||
if(ret != -1)
|
||||
{
|
||||
LOG("Failed: open was expected to fail, but returned %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
ret = open("/dev/urandom", O_RDWR);
|
||||
if(ret != -1)
|
||||
{
|
||||
LOG("Failed: open O_RDWR was expected to fail, but returned %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
ret = open("/dev/urandom", O_RDONLY);
|
||||
if(ret == -1)
|
||||
{
|
||||
LOG("Failed: open was expected to succceed, but returned %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_seccomp_vow()
|
||||
{
|
||||
int ret = test_successful_exit(&do_test_seccomp_vow_open);
|
||||
if(ret != 0)
|
||||
{
|
||||
LOG("Failed: do_test_seccomp_vow_open()\n");
|
||||
return 1;
|
||||
}
|
||||
ret = test_successful_exit(&do_test_seccomp_vow_socket);
|
||||
if(ret != 0)
|
||||
{
|
||||
LOG("Failed: do_test_seccomp_vow_socket()\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_seccomp_exile_vow_multiple()
|
||||
{
|
||||
|
||||
int ret = exile_vow(EXILE_SYSCALL_VOW_STDIO | EXILE_SYSCALL_VOW_UNIX | EXILE_SYSCALL_VOW_SECCOMP_INSTALL | EXILE_SYSCALL_VOW_DENY_ERROR);
|
||||
if(ret != 0)
|
||||
{
|
||||
LOG("Failed: exile_vow() call 1 failed\n");
|
||||
return 1;
|
||||
}
|
||||
int s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if(s == -1)
|
||||
{
|
||||
LOG("Failed: socket was expected to succeed, but returned %i\n", s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Let's take away unix sockets, so it should not be possible anymore */
|
||||
ret = exile_vow(EXILE_SYSCALL_VOW_STDIO | EXILE_SYSCALL_VOW_SECCOMP_INSTALL | EXILE_SYSCALL_VOW_DENY_ERROR);
|
||||
if(ret != 0)
|
||||
{
|
||||
LOG("Failed: exile_vow() call 2 failed\n");
|
||||
return 1;
|
||||
}
|
||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if(s != -1)
|
||||
{
|
||||
LOG("Failed: socket was expected to fail, but returned %i\n", s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Let's try to regain unix sockets again */
|
||||
ret = exile_vow(EXILE_SYSCALL_VOW_STDIO | EXILE_SYSCALL_VOW_UNIX | EXILE_SYSCALL_VOW_SECCOMP_INSTALL | EXILE_SYSCALL_VOW_DENY_ERROR);
|
||||
if(ret != 0)
|
||||
{
|
||||
LOG("Failed: exile_vow() call 3 failed\n");
|
||||
return 1;
|
||||
}
|
||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if(s != -1)
|
||||
{
|
||||
LOG("Failed: socket was still expected to fail, but returned %i\n", s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if HAVE_LANDLOCK == 1
|
||||
int test_landlock()
|
||||
{
|
||||
if(!exile_landlock_is_available())
|
||||
{
|
||||
LOG("landlock not available, so cannot test\n");
|
||||
return 1;
|
||||
}
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
exile_append_path_policy(policy, EXILE_FS_ALLOW_READ, "/proc/self/fd");
|
||||
exile_append_path_policies(policy, EXILE_FS_ALLOW_ALL_READ, "/proc/self/fd");
|
||||
xexile_enable_policy(policy);
|
||||
|
||||
int fd = open("/", O_RDONLY | O_CLOEXEC);
|
||||
@ -217,7 +420,7 @@ int test_landlock()
|
||||
int test_landlock_deny_write()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
exile_append_path_policy(policy, EXILE_FS_ALLOW_READ, "/tmp/");
|
||||
exile_append_path_policies(policy, EXILE_FS_ALLOW_ALL_READ, "/tmp/");
|
||||
xexile_enable_policy(policy);
|
||||
|
||||
int fd = open("/tmp/a", O_WRONLY | O_CLOEXEC);
|
||||
@ -248,14 +451,14 @@ int test_nofs()
|
||||
int s = socket(AF_INET,SOCK_STREAM,0);
|
||||
if(s == -1)
|
||||
{
|
||||
fprintf(stderr, "Failed to open socket but this was not requested by policy\n");
|
||||
LOG("Failed to open socket but this was not requested by policy\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Expect seccomp to take care of this */
|
||||
if(open("/test", O_CREAT | O_WRONLY) >= 0)
|
||||
{
|
||||
fprintf(stderr, "Failed: We do not expect write access\n");
|
||||
LOG("Failed: We do not expect write access\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -271,14 +474,14 @@ int test_no_new_fds()
|
||||
|
||||
if(open("/tmp/test", O_CREAT | O_WRONLY) >= 0)
|
||||
{
|
||||
fprintf(stderr, "Failed: Could open new file descriptor\n");
|
||||
LOG("Failed: Could open new file descriptor\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int s = socket(AF_INET,SOCK_STREAM,0);
|
||||
if(s >= 0)
|
||||
{
|
||||
fprintf(stderr, "Failed: socket got opened but policy denied\n");
|
||||
LOG("Failed: socket got opened but policy denied\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -286,6 +489,178 @@ int test_no_new_fds()
|
||||
|
||||
}
|
||||
|
||||
extern int mkpath(const char *p, mode_t mode, int baseisfile);
|
||||
int test_mkpath()
|
||||
{
|
||||
system("rm -rf /tmp/.exile.h/");
|
||||
const char *filepath = "/tmp/.exile.h/test_mkpath/some/sub/dir/file";
|
||||
const char *dirpath = "/tmp/.exile.h/test_mkpath/some/other/sub/dir";
|
||||
int ret = mkpath(filepath, 0700, 1);
|
||||
if(ret != 0)
|
||||
{
|
||||
LOG("Failed: mkpath(file) returned: %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
ret = mkpath(dirpath, 0700, 0);
|
||||
if(ret != 0)
|
||||
{
|
||||
LOG("Failed: mkpath(dirpath) returned: %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct stat statbuf;
|
||||
ret = stat(filepath, &statbuf);
|
||||
if(ret != 0)
|
||||
{
|
||||
LOG("Failed: stat on filepath returned: %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
if(!S_ISREG(statbuf.st_mode))
|
||||
{
|
||||
LOG("Failed: mkpath did not create a file: %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
ret = stat(dirpath, &statbuf);
|
||||
if(ret != 0)
|
||||
{
|
||||
LOG("Failed: stat on dirpath returned: %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
if(!S_ISDIR(statbuf.st_mode))
|
||||
{
|
||||
LOG("Failed: mkpath did not create a directory: %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
system("rm -rf /tmp/.exile.h/");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_fail_flags()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
exile_append_path_policies(policy, EXILE_FS_ALLOW_ALL_READ, "/nosuchpathexists");
|
||||
int ret = exile_enable_policy(policy);
|
||||
if(ret == 0)
|
||||
{
|
||||
fprintf(stderr, "Failed: A path that does not exist should have set the error flag %i\n", ret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int *read_pipe = NULL;
|
||||
int do_launch_test(void *arg)
|
||||
{
|
||||
int num = *(int *)(arg);
|
||||
num += 1;
|
||||
char buffer[512] = { 0 };
|
||||
read(*read_pipe, buffer, sizeof(buffer)-1);
|
||||
printf("Sandboxed +1: %i\n", num);
|
||||
printf("Echoing: %s\n", buffer);
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_launch()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
struct exile_launch_params params = { 0 };
|
||||
struct exile_launch_result res = {0};
|
||||
int num = 22;
|
||||
params.func = &do_launch_test;
|
||||
params.funcarg = #
|
||||
params.policy = policy;
|
||||
read_pipe = ¶ms.child_write_pipe[0];
|
||||
int launchfd = exile_launch(¶ms, &res);
|
||||
if(launchfd < 0)
|
||||
{
|
||||
LOG("Failed to launch\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char buffer[4096] = { 0 };
|
||||
write(res.write_fd, "1234", 4);
|
||||
int s = read(res.read_fd, buffer, sizeof(buffer)-1);
|
||||
write(1, buffer, s);
|
||||
LOG("Before wait, got: %i\n", s);
|
||||
fflush(stdout);
|
||||
if(strstr(buffer, "Echoing: 1234") == NULL)
|
||||
{
|
||||
LOG("Failed: Did not get back what we wrote\n");
|
||||
}
|
||||
int status = 0;
|
||||
waitpid(res.tid, &status, __WALL);
|
||||
if(WIFEXITED(status))
|
||||
{
|
||||
status = WEXITSTATUS(status);
|
||||
return status;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
#define LAUNCH_GET_TEST_STR "Control yourself. Take only what you need from it.\n"
|
||||
int do_launch_get_test(void *a)
|
||||
{
|
||||
fprintf(stdout, LAUNCH_GET_TEST_STR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_launch_get()
|
||||
{
|
||||
struct exile_policy *policy = exile_init_policy();
|
||||
struct exile_launch_params params = { 0 };
|
||||
params.func = &do_launch_get_test;
|
||||
params.funcarg = NULL;
|
||||
params.policy = policy;
|
||||
|
||||
size_t n = 0;
|
||||
char *content = exile_launch_get(¶ms, &n);
|
||||
unsigned int len = strlen(LAUNCH_GET_TEST_STR);
|
||||
if(n != strlen(LAUNCH_GET_TEST_STR))
|
||||
{
|
||||
LOG("Lenght does does not match: %lu vs %u\n", n, len);
|
||||
return 1;
|
||||
}
|
||||
if(strcmp(content, LAUNCH_GET_TEST_STR) != 0)
|
||||
{
|
||||
LOG("Received content differs\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_vows_from_str()
|
||||
{
|
||||
uint64_t expected = EXILE_SYSCALL_VOW_CHOWN | EXILE_SYSCALL_VOW_WPATH | EXILE_SYSCALL_VOW_INET | EXILE_SYSCALL_VOW_DENY_ERROR;
|
||||
uint64_t actual = exile_vows_from_str("chown wpath inet error");
|
||||
if(expected != actual)
|
||||
{
|
||||
LOG("Masks don't match: %lu vs %lu\n", expected, actual);
|
||||
return 1;
|
||||
}
|
||||
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
|
||||
{
|
||||
char *name;
|
||||
@ -299,11 +674,21 @@ struct dispatcher dispatchers[] = {
|
||||
{ "seccomp-x32-kill", &test_seccomp_x32_kill},
|
||||
{ "seccomp-require-last-matchall", &test_seccomp_require_last_matchall},
|
||||
{ "seccomp-errno", &test_seccomp_errno},
|
||||
{ "seccomp-group", &test_seccomp_group},
|
||||
{ "seccomp-argfilter-allowed", &test_seccomp_argfilter_allowed},
|
||||
{ "seccomp-argfilter-filtered", &test_seccomp_argfilter_filtered},
|
||||
{ "seccomp-argfilter-mixed", &test_seccomp_argfilter_mixed},
|
||||
{ "seccomp-vow", &test_seccomp_vow},
|
||||
{ "seccomp-vow-exile_vow-multi", &test_seccomp_exile_vow_multiple},
|
||||
{ "landlock", &test_landlock},
|
||||
{ "landlock-deny-write", &test_landlock_deny_write },
|
||||
{ "no_fs", &test_nofs},
|
||||
{ "no_new_fds", &test_no_new_fds}
|
||||
{ "no_new_fds", &test_no_new_fds},
|
||||
{ "mkpath", &test_mkpath},
|
||||
{ "failflags", &test_fail_flags},
|
||||
{ "launch", &test_launch},
|
||||
{ "launch-get", &test_launch_get},
|
||||
{ "vow_from_str", &test_vows_from_str},
|
||||
{ "clone3_nosys", &test_clone3_nosys},
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
92
test.cpp
Parasts fails
92
test.cpp
Parasts fails
@ -0,0 +1,92 @@
|
||||
#include "exile.hpp"
|
||||
#include "assert.h"
|
||||
#include <map>
|
||||
|
||||
std::string sandboxed_reverse(std::string str)
|
||||
{
|
||||
std::reverse(str.begin(), str.end());
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t stdstrlen(const std::string &str)
|
||||
{
|
||||
return str.size();
|
||||
}
|
||||
|
||||
int incrementer(int arg)
|
||||
{
|
||||
return ++arg;
|
||||
}
|
||||
int test_exile_launch_trivial()
|
||||
{
|
||||
int u = 22;
|
||||
int result = exile_launch<int>(exile_init_policy(), &incrementer, u);
|
||||
assert(result == 23);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_exile_launch_stdstring()
|
||||
{
|
||||
std::string str = "abc123";
|
||||
std::string reversed = exile_launch<std::string>(exile_init_policy(), &sandboxed_reverse, str);
|
||||
assert(reversed == "321cba");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct not_trivially_copyable
|
||||
{
|
||||
public:
|
||||
std::string somecontent;
|
||||
};
|
||||
|
||||
int test_exile_launch_serializer()
|
||||
{
|
||||
static_assert(! std::is_trivially_copyable_v<not_trivially_copyable>);
|
||||
|
||||
auto serializer = [](const not_trivially_copyable &obj, char *buf, size_t n){
|
||||
serialize_stdstring<std::string>(obj.somecontent, buf, n);
|
||||
return obj.somecontent.size();
|
||||
};
|
||||
|
||||
auto deserializer = [](const char *buffer, size_t n) {
|
||||
not_trivially_copyable obj;
|
||||
obj.somecontent = deserialize_stdstring<std::string>(buffer, n);
|
||||
return obj;
|
||||
};
|
||||
|
||||
not_trivially_copyable result = exile_launch<not_trivially_copyable>(exile_init_policy(), serializer, deserializer, []() {not_trivially_copyable obj; obj.somecontent = "Just something"; return obj;});
|
||||
|
||||
assert(result.somecontent == "Just something");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if(argc < 2)
|
||||
{
|
||||
std::cerr << "Missing test" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::map<std::string, int (*)()> map = {
|
||||
{ "launch-trivial-cpp", &test_exile_launch_trivial} ,
|
||||
{ "launch-stdstring-cpp", &test_exile_launch_stdstring },
|
||||
{ "launch-serializer-cpp", &test_exile_launch_serializer },
|
||||
};
|
||||
|
||||
std::string test = argv[1];
|
||||
if(test == "--dumptests")
|
||||
{
|
||||
for(auto &entry : map)
|
||||
{
|
||||
std::cout << entry.first << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int (*fn)() = map[test];
|
||||
if(fn != nullptr)
|
||||
{
|
||||
return fn();
|
||||
}
|
||||
std::cerr << "Unknown test" << std::endl;
|
||||
return 1;
|
||||
}
|
18
test.sh
18
test.sh
@ -44,14 +44,15 @@ function runtest_skipped()
|
||||
|
||||
function runtest()
|
||||
{
|
||||
testname="$1"
|
||||
test_log_file="$2"
|
||||
testbin="$1"
|
||||
testname="$2"
|
||||
test_log_file="$3"
|
||||
|
||||
echo "Running: $testname. Date: $(date)" > "${test_log_file}"
|
||||
|
||||
echo -n "Running $1... "
|
||||
echo -n "Running $testname... "
|
||||
#exit $? to suppress shell message like "./test.sh: line 18: pid Bad system call"
|
||||
(./test $1 || exit $?) &>> "${test_log_file}"
|
||||
(./$testbin "$testname" || exit $?) &>> "${test_log_file}"
|
||||
ret=$?
|
||||
SUCCESS="no"
|
||||
if [ $ret -eq 0 ] ; then
|
||||
@ -64,7 +65,7 @@ function runtest()
|
||||
runtest_fail
|
||||
fi
|
||||
|
||||
echo "Finished: ${testname}. Date: $(date). Success: $SUCCESS" >> "${test_log_file}"
|
||||
echo "Finished: ${testname} (${testbin}). Date: $(date). Success: $SUCCESS" >> "${test_log_file}"
|
||||
}
|
||||
|
||||
GIT_ID=$( git log --pretty="format:%h" -n1 )
|
||||
@ -79,7 +80,12 @@ LOG_OUTPUT_DIR_PATH="${LOG_OUTPUT_DIR}/exile_test_${GIT_ID}_${TIMESTAMP}"
|
||||
|
||||
for test in $( ./test --dumptests ) ; do
|
||||
testname=$( echo $test )
|
||||
runtest "$testname" "${LOG_OUTPUT_DIR_PATH}/log.${testname}"
|
||||
runtest test "$testname" "${LOG_OUTPUT_DIR_PATH}/log.${testname}"
|
||||
done
|
||||
|
||||
for test in $( ./testcpp --dumptests ) ; do
|
||||
testname=$( echo $test )
|
||||
runtest testcpp "$testname" "${LOG_OUTPUT_DIR_PATH}/log.${testname}"
|
||||
done
|
||||
echo
|
||||
echo "Tests finished. Logs in $(realpath ${LOG_OUTPUT_DIR_PATH})"
|
||||
|
Atsaukties uz šo jaunā problēmā
Block a user