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.