However, this doesn’t works with dynamic libraries.
It does work for dynamic libraries. If a shared object is located on a partition which is mounted with the noexec option, it cannot be loaded, otherwise noexec
would be quite useless.
$ grep -E '/tmp |ext4' /proc/mounts
/dev/mapper/root_crypt / ext4 rw,nodev,noatime,data=ordered 0 0
tmpfs /tmp tmpfs rw,nosuid,nodev,noexec,noatime,size=2031200k 0 0
$ cat > main.c
#include <stdio.h>
void main(void)
{
printf("%d\n", getpid());
}
$ gcc -o main main.c
$ ./main
4950
$ cat > shared.c
int getpid(void)
{
return 1;
}
$ gcc -shared -fPIC -o shared.so shared.c
$ LD_PRELOAD=./shared.so ./main
1
$ mv shared.so /tmp
$ LD_PRELOAD=/tmp/shared.so ./main
ERROR: ld.so: object '/tmp/shared.so' from LD_PRELOAD cannot be preloaded (failed to map segment from shared object): ignored.
4978
If you want to use seccomp to prevent executing untrusted shared objects, you can do that by restricting calls to mmap()
, mprotect()
, and obviously execve()
. Make sure that the process can't map anything with PROT_EXEC
. Restricting files is not enough, because any arbitrary data can be passed to mmap()
through a file descriptor, and mprotect()
can change the permissions of arbitrary pages of memory to make them executable. Additionally, since this example is a blacklist rather than a whitelist, you'll also have to deny access to some ptrace()
arguments, because they can be used to break out of a seccomp sandbox.
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(mmap), 1,
SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC, PROT_EXEC));
if (rc == -1)
goto out;
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCESS), SCMP_SYS(mprotect), 1,
SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC, PROT_EXEC));
if (rc == -1)
goto out;
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCESS), SCMP_SYS(execve), 0);
if (rc == -1)
goto out;
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(ptrace), 1,
SCMP_A0(SCMP_CMP_EQ, PTRACE_POKEUSER));
if (rc == -1)
goto out;
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(ptrace), 1,
SCMP_A0(SCMP_CMP_EQ, PTRACE_SETREGS));
if (rc == -1)
goto out;
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(ptrace), 1,
SCMP_A0(SCMP_CMP_EQ, PTRACE_SETREGSET));
if (rc == -1)
goto out;
There are probably ways to bypass this seccomp snippet that I haven't thought about, so this is just to give you an idea of what it takes.
I've never used NaCl so I can't say how you'd restrict execution with it.