Sandboxing: Conclusion

In total I’ve written five methods for sandboxing code. These are certainly not the only methods but they’re mostly simple to use, and they’re what I’ve personally used.

A large part of this sandboxing was only possible because I built the code to work this way. I split everything into privileged and unprivileged groups, and I determined my attack surface. By moving the sandboxing after the privileged code and before the attack surface I minimized risk of exploitation. Considering security before you write any code will make a very big difference.

One caveat here is that SyslogParse can no longer write files. What if, after creating rules for iptables and apparmor, I want to write them to files? It seems like I have to undo all of my sandboxing. But I don’t – there is a simple way to do this. All I need is to have SyslogParse spawned by another privileged process, and have that process get the output from SyslogParse, validate it, and then write that to a file.

One benefit of this “broker” process architecture is that you can actually move all of the privileged code out of SyslogParse. You can launch it in another user, in a chroot environment, and pass it a file descriptor or buffer from the privileged parent.

The downside is that the parent must remain root the entire time, and flaws in the parent could lead to it being exploited – attacks like this should be difficult as the broker could would be very small.

Hopefully others can read these articles and apply it to their own programs. If you build a program with what I’ve written in mind it’s very easy to write sandboxed software, especially with a broker architecture. You’ll make an attacker miserable if you can make use of all of this – their only real course of action is to attack the kernel, and thanks to seccomp you’ve made that a pain too.

Before you write your next project, think about how you can lock it down before you start writing code.

If you have anything to add to what I’ve written – suggestions, corrections, random thoughts – I’d be happy to read comments about it and update the articles.

Here’s a link to all of the articles:

Seccomp Filters: http://www.insanitybit.com/2014/09/08/3719/

Linux Capabilities: http://www.insanitybit.com/2014/09/08/sandboxing-linux-capabilities/

Chroot Sandbox: http://www.insanitybit.com/2014/09/08/sandboxing-chroot-sandbox/

Apparmor: http://www.insanitybit.com/2014/09/08/sandboxing-apparmor/

And here’s a link to the GitHub for SyslogParse:

https://github.com/insanitybit/SyslogParser

Sandboxing: Apparmor

Sandboxing: Apparmor

This is the fifth installment on a series of various sandboxing techniques that I’ve used in my own code to restrict an applications capabilities. You can find a shorter overview of these techniques here. This article will be discussing sandboxing with Apparmor.

Mandatory Access Control:

Mandatory Access Control (MAC), like Discretionary Access Control (DAC), is meant to define permissions for a program. Users and Groups are DAC. But what if you want to confine a program with full root? As discussed, root with full capabilities is quite dangerous – and in the case of SyslogParser quite a few of those capabilities are necessary.

Apparmor is a form of Mandatory Access Control implemented through the Linux Security Module hooks in the Linux kernel. MAC is “administrator” defined policy, and can confine even root applications.

Apparmor is a *bit* out of scope for this series, as it doesn’t actually involve any code, but it’s still relevant.

The Code:

While Apparmor itself doesn’t have code in SyslogParse, here’s the profile for the program.


# Last Modified: Wed Aug 13 18:57:15 2014
#include

/usr/bin/syslogparse{

/usr/bin/syslogparse mr,
/var/log/* mr,

/etc/ld.so.cache mr,

/sys/devices/system/cpu/online r,

/lib/@{multiarch}/libgcc_s.so* mr,
/lib/@{multiarch}/libc-*.so mr,
/lib/@{multiarch}/libm-*.so mr,
/lib/@{multiarch}/libpthread*.so mr,

/usr/lib/@{multiarch}/libseccomp.so* mr,
/usr/lib/@{multiarch}/libcap-ng*.so* mr,

/usr/lib/@{multiarch}/libstdc*.so* mr,

}

Apparmor is incredibly straight forward. There is a path, and then there is one or more letters. These letters stand for certain things.

r = read
m = map
w = write

All of this is pretty straight forward. SyslogParse gets the number of CPU cores from /sys/devices/system/cpu/online , so it needs “r” access.

It needs to read some libraries in order to function.

And that’s it. Sort of… apparmor on my system is, unfortunately, quite broken. The tools for enforcing/ complaining crash on me (I have a lot of weird profiles that I experiment with), which is actually why I started building SyslogParse. So this profile is a bit incomplete. It still needs some capabilities defined for chroot, setuid/setgid, and possibly more file access.

Conclusion:

When enabled an Apparmor profile will begin enforcing policy as soon as the process begins. That means that, even if running as root, an attacker is always confined to those files defined in the profile. Apparmor is quite powerful, and combined with the other sandboxing techniques used it’s a very nice reinforcement – writing to the chroot, for example, is denied throughout the process by both DAC and MAC now.

Apparmor is, unfortunately, only available on certain distributions.

Next Up: Final Conclusion

Sandboxing: Chroot Sandbox

Sandboxing: Limited Users

This is the fourth installment on a series of various sandboxing techniques that I’ve used in my own code to restrict an applications capabilities. You can find a shorter overview of these techniques here. This article will be discussing sandboxing a program using Limited Users.

Users and Groups:

Linux Discretionary Access Control works by separating and grouping applications into ‘users’ and ‘groups’. A process in user A is, in terms of DAC, isolated from a process in user B.

There’s also user 0, the root user, which is a privileged user account.

Only a program with root, or with CAP_SETUID / CAP_SETGID can manipulate its own UID/GID. In the case of SyslogParse, we have root, and we definitely want to lose it when we can.

So, after getting the file handles we need, here’s the code for dropping to a limited user account (if you’ve read the previous articles this happens right after the chroot).


if (setgid(65534) != 0)
err(0, "setgid failed.");
if (setuid(65534) != 0)
err(0, "setuid failed.");

Very simple. So here’s a simple explanation.


if (setgid(65534) != 0)
err(0, "setuid failed.");

setgid(65534) sets the GID to 65534. This is the “nobody” group on my system. Nobody is an unprivileged user often used by programs wanting to drop privileges. If 65534 doesn’t exist, all the better – dropping to a GID that doesn’t exist is great.


if (setuid(65534) != 0)
err(0, "setgid failed.");

setuid(65534) is changing the user to 65534, which, as above, is the nobody user. Same as before, if the user doesn’t exist, that’s dandy.

Conclusion:

Dropping privileges is a hugely beneficial thing to do. By separating the code into a “privileged stuff done all at once, then never again” you can drop privileges before doing anything dangerous, and there goes an attackers ability to escalate.

Dropping root privileges is incredibly important. The attack surface and amount of post-exploitation work an attacker can do shrinks drastically.

In the case of SyslogParse, as any attacks would be for local escalation (it does no networking), an attacker would probably lose privileges by exploiting it if going from any normal compromised process. At this stage they are in a chroot with no read or write access, running in an unprivileged user/ group with no capabilities, they have access to 22 system calls and some very nice to have calls, such as read() are denied, and their only chance for getting a few capabilities is by exploiting a few lines of code that involve opening a file.

I was going to have the next section be on rlimit, but it’s really not important and also not viable unless you’ve built the application from the bottom up to never write to a file, which will typically involve a broker’d architecture.

Next Up: Apparmor

Sandboxing: Linux Capabilities

This is the second installment on a series of various sandboxing techniques that I’ve used in my own code to restrict an applications capabilities. You can find a shorter overview of these techniques here. This article will be discussing Linux Capabilities.

Intro To Linux Capabilities:

On Linux you’re likely familiar with the root user. Root is the ‘admin’ account of the system, it has privileges that other processes don’t. But, what you may not have known, is that those privileges given to root are actually enumerable and defined. For example, root has the capability CAP_SYS_CHROOT, which is what allows it to call chroot().

Let’s say a program needs root, but only because it calls chroot at some point. Instead of giving all of the privileges except CAP_SYS_CHROOT.

So, if your program has to run as root (as mine does), you can actually drop some of your root privileges while maintaining others. How effective is this? Jump down to the conclusion below to see – hint: it can go between great and awful.

The Code: (includes should have a # in front, but WP is mean)

include include

capng_clear(CAPNG_SELECT_BOTH);
capng_updatev(CAPNG_ADD, (capng_type_t)(CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT, CAP_DAC_READ_SEARCH, -1);
capng_apply(CAPNG_SELECT_BOTH);

Let’s break this down ~line by ~line.


include include

This includes the headers for linux capabilities (so that you can refer to them as their type) and cap-ng, the library we’ll be using to actually drop privileges.


capng_clear(CAPNG_SELECT_BOTH);

This line will clear all privileges. If you were to apply this, you’d have essentially dropped all root privileges.


capng_updatev(CAPNG_ADD, (capng_type_t)(CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT, CAP_DAC_READ_SEARCH, -1);

This line is where we state which capabilities we’d like. After the capng_clear() we have none, but the program does need a few.

The first two parameters are effectively saying to add these rules.

The third, fourth, and fifth parameters are the defined capabilities to allow.

The last parameter is a -1, which lets capng know that your list of capabilities is terminated.


capng_apply(CAPNG_SELECT_BOTH);

And now, with this call, the rules are applied. Only these capabilities are given to the program… “only”.

Conclusion:
This was really easy to do. Three lines of code and a large number of capabilities are gone. But, what’s left?

CAP_SETUID/ CAP_SETGID : Quite dangerous, as it means you can interact with processes of other UID/GID’s by simply making your UID/GID the same as theirs.

CAP_SYS_CHROOT : Not as scary, you can chroot, and if you retain the ability to chroot you can then break out of that.

CAP_DAC_READ_SEARCH : You can read all files that root can read. Password files, sensitive files, whatever. All yours to read.

So in a lot of ways you’re just dropping from root…. to root. You’re still quite powerful and dangerous if you drop these capabilities, it’s not a very large barrier. An attacker who gains the above privileges still gains quite a lot. But, in the case of SyslogParse, all capabilities are dropped eventually.

The nice thing about capabilities is you can do it as soon as the program starts. After you’ve gotten your file descriptors and all that, you can go ahead and start real sandboxing, then do the actual dangerous stuff. In this case, I had to give a lot of scary permissions. But for someone else, maybe all they need is to bind port 80, and in that case you just give CAP_NET_BIND_SERVICE, drop everything else, and that’s pretty nice.

It honestly feels like a “Well, it’s better than giving it full root” in this case, which is bittersweet. It still pretty much feels like full root. But uh, hey, it’s better than giving it full root.

Sandboxing: Seccomp Filters

This is the first installment on a series of various sandboxing techniques that I’ve used in my own code to restrict an applications capabilities. You can find a shorter overview of these techniques here. This article will be discussing seccomp filters.

What is Seccomp? An Introduction:

System calls are your way of asking the kernel to do something for you. You send a message saying “Hey, open a file for me” and it’ll probably do it for you, barring permission errors or some other issue. But, if you can talk to the kernel, you can exploit the kernel. Many vulnerabilities are found in kernel system calls, leading to full root privileges – bypassing sandboxing techniques like SELinux, Apparmor, namespaces, chroots, you name it. So, how do we deal with this without patching the kernel, as a developer? Seccomp filters.

Seccomp is a way for a program to register a set of rules with the kernel. These rules deal with the system calls a program can make, and which parameters it can send with them.

When you create your rules you get a nice overview of your kernel attack surface. Those calls are the ways your attacker can attack the kernel. On top of that ,you’ve just reduced kernel attack surface – if an attacker requires system call A and you’ve only allowed system calls B through D, they can’t attack with system call A.

Another nice benefit is the ability to restrict capabilities. If your program never writes a file, don’t give it access to the write() system call. Now you’ve reduced the kernel attack surface, but you’ve also stopped the program from writing files.

The Code:

Seccomp code is fairly simple to use, though I haven’t found any really good documentation. Here is the seccomp code used in my program, SyslogParse, to restrict its system calls.


scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_KILL);

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(tgkill), 0);

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(access), 0);

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 2,
SCMP_A0(SCMP_CMP_GE, 1),
SCMP_A0(SCMP_CMP_LE, 2)
);

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 1,
SCMP_A2(SCMP_CMP_NE, PROT_EXEC)
);

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 2,
SCMP_A0(SCMP_CMP_EQ, NULL),
SCMP_A5(SCMP_CMP_EQ, 0)
);

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 2,
SCMP_A0(SCMP_CMP_NE, NULL),
SCMP_A1(SCMP_CMP_GE, 0)
);

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(madvise), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(execve), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 0);

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getrlimit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(set_robust_list), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(set_tid_address), 0);

if(seccomp_load(ctx) != 0) //activate filter
err(0, “seccomp_load failed”);

I’ll go through this bit by bit.


scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_KILL);

This should be fairly simple to understand if you’ve written basically any code. This instantiates the seccomp filter, “ctx”, and then initializes it to kill on rule violations. Simple.


seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0);

This line is a rule for the “futex” system call. The first parameter, “ctx”, is our instantiated filter. “SCMP_ACT_ALLOW”, the second parameter, is saying to allow when a condition is met. The third is a macro for the futex() system call, as that’s the call we want to allow through the filter. The last parameter, “0”, is how many rules we want to add to this that deal with parameters.

Simple. So this rule will allow any futex system call regardless of parameters.

I chose futex in this example to demonstrate that seccomp can not protect you from every attack. Despite the heavy amount of sandboxing I’ve done in this program, this filter will do nothing to stop attacks that use the futex system call. Recently, one vulnerability was found that could do just that – a call to futex would lead to control over the kernel. Seccomp just isn’t all powerful, but it’s a big improvement.

Note: I found all of these syscalls by repeatedly running strace on SyslogParse with different parameters. Strace will list all of the system calls as well as their arguments and makes creating rules very easy.


if(seccomp_load(ctx) != 0) //activate filter
err(0, "seccomp_load failed");

seccomp_load(ctx) will load up the filter and from this point on it is enforced. In this case I’ve wrapped it to ensure that it either loads properly or the program won’t run.

And that’s it. That’s all the code it takes. If the program makes a call to any other system call it crashes with “Bad System Call”.

Seccomp is quite easy to use and is the first thing I’d make use of if you are considering sandboxing. All sandboxing relies on a strong keernel, but as a developer you can only change your own program, and seccomp is a good way to reduce kernel attack surface and make all other sandboxes more effective.

Linux has something like 200 system calls (can’t find a good source, anyone know a more definitive number?), and SyslogParse has dropped that down to about 22. That’s a nice drop in privileges and attack surface.

Next Up: Linux Capabilities

Hardening DNSCrypt

DNSCrypt is a DNS Resolver that encrypts the DNS requests between you and the first level DNS resolver. I have a guide for setting it up here. This guide will be about restricting the process and user account, making DNSCrypt more resilient to attack – I will continue to update this guide, I have a few more ideas.

One of the nice features of DNSCrypt is that it actually takes security into account. I wish this weren’t something to be shocked by, but, *gasp* it actually uses compiler security flags. Specifically, it uses the following flags:

-fPIC -fPIE -fstack-protector-all -fno-strict-overflow -fwrapv **

-fPIC and -fPIE tell the compiler to create a relocatable binary, completing the implementation of ASLR. It’s a mitigation technique we rarely seen used, despite it being somewhat critical, and it having been around for years. So right off the bat they’re doing more than most.

-fstack-protector-all (unlike the oft used -fstack-protector, which only protects functions using char arrays/strings) tells the compiler to protect every function with a stack canary. If an overflow occurs the canary may be overwritten, and the function will fail.

-fno-strict-overflow and -fwrapv are essentially the same (in other words, I don’t know the difference) and they tell GCC to not make assumptions about overflows, basically to not assume that overflows won’t occur. Compilers make the assumption that overflows won’t happen when they generate the optimized assembly, so they can build optimizations with that assumption – this prevents that, which is safer.

So these are nice, and we like them. But DNSCrypt also does a bit more.

You can create a new DNSCrypt user with no write rights, and it will chroot itself into that user, and drop rights. This is great, since a chroot’d process with no ability to write is difficult to break out of. And running as a separate user means no X11 access, it gets its own home folder, and it’s generally more isolated from the system – all good things!

But it means some other stuff too. Because it does all of the above we as users can take that protection further – beyond where typical programs allow us to. I think this demonstrates what a strong security model really can do when built from the ground up.

So, on to what we can do.

First thing’s first, we’re going to want some information on our DNSCrypt user.

run ‘id dnscrypt’

You should get something similar to:

id dnscrypt
uid=109(dnscrypt) gid=123(dnscrypt) groups=123(dnscrypt)

We’re going to need this.

IPTables On User

Note that if you’re using UFW this may cause issues, using UFW/GUFW with iptables isn’t recommended, and your mileage may vary  – to remove your UFW rules run ‘iptables -F’. 

Normally I’m not fond of outbound filtering, but because DNSCrypt separates itself into another user, it’s actually not such a bad idea. It means that DNSCrypt can’t just switch its outbound connection to another program under the same user account, and it means that the ports we limit will be limited to that user account specifically. This assumes you are using DNSCrypt under a user called ‘dnscrypt’.

So it’s a lot more worthwhile to set up outbound filtering here.

DNSCrypt should only need outbound access to port 443, with UDP. So we can restrict it to just port 443 and UDP with the following IPTables rules:

iptables -A OUTPUT -m owner --uid-owner dnscrypt -p udp  --dport 443 -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner dnscrypt -j DROP

Basically, the first rule allows outbound access to the DNSCrypt user over port 443 and UDP, and the second rule denies everything. If the first rule is hit, and it passes, the second rule doesn’t have to come into play.

***

DNSCrypt is now restricted to UDP over port 443, and all processes running under the dnscrypt user are as well. If you followed the tip then no new connections can be made to your system except over port 53 (you can have dnscrypt use another port, in which case you’ll switch that port to whatever that one is. I have yet to figure the details of this out, I’ll edit it in when I do.)

Trusted Path Execution

If you care about security you’re already running Grsecurity, but if not, see my guide here.

Grsecurity has an option called Trusted Path Execution that allows us to limit a group, preventing it from executing files owned and only writable by root – since our program doesn’t run as root, and can’t write anywhere, it means it won’t be able to execute anything at all.

So check the TPE box and add the GID for untrusted users, in this case 123.

Now this protection is superfluous, DNSCrypt shouldn’t be able to write to the filesystem, so it shouldn’t be able to execute any payloads off of the file system, but it’s still good to have as the protection is now implemented by the user account itself, and doesn’t rely on the program to drop rights properly, or a perfect implementation of chroot.

Chroot Restrictions

While you’re compiling your Grsecurity kernel, you can also go ahead and turn on every single chroot restriction without worry – DNSCrypt works fine with them all. DNSCrypt already can’t write to its chroot, so  as far as I know there’s no known bypass as is, but you can safely enable all of these restrictions. Although some of the protections are a bit redundant due to the aforementioned write restrictions, there are a few that are quite nice, such as:

CONFIG_GRKERNSEC_CHROOT_FINDTASK

CONFIG_GRKERNSEC_CHROOT_CAPS

More restrictions on our exposed service.

Apparmor

Apparmor is an LSM (Linux Security Module) program that restricts a process. If Apparmor is the LSM used on your distribution (Ubuntu derivatives) you can find my profile here. Apparmor will restrict file access, what programs can be executed, what libraries can be loaded, etc. An attacker who winds up in a program that is confined with apparmor must either find a flaw in apparmor, or the profile, or they have to use a local escalation attack. If you’re using everything listed above this is going to be a lot of work for them.

Users of other LSM such as SELinux will need to build their own profiles. This shouldn’t be hard, DNSCrypt needs little file access to work.

Conclusion

Given the situation where an attacker finds himself compromosing the DNSCrypt-Proxy on a system that has done all of the above, they’re going to be pretty pissed off. There is still room for improvement, (seccomp filters) but right now an attacker is going to have to do a lot to get an exploit to be reliable.

For a program like DNSCrypt this level of security is great. It already chroots itself to a directory that it can’t write to, and they use compiler security, so you know they’re taking this stuff seriously. That’s what allows us to spend our time securing it further. If DNSCrypt did not so gracefully run as another user, and if it weren’t built to drop its rights to the extent that it does, then our apparmor profile would be more convoluted, TPE may not be possible, and an outbound Firewall would have been a useless attempt at security through obscurity. But because it’s built from the ground up to be this way we can reinforce it well.

Notes/ Tips

Much of this can be done to any process/ service with a bit of a change, but it’s nice to be able to do this to a process like DNSCrypt.

**

Keep in mind that you can add your own files to the makefile, such as “-march=native”, optimizing for your CPU. I can’t guarantee that this will play nice, or that it won’t add in unsafe compiler optimization! But you may end up using something like AES instructions since this deal swith crypto, and math, and this could speed things up.

***

Tip: The following commands will set your firewall so that:

1) If a connection is new, is over the loopback interface, is udp, and uses port 53, we accept it (allows dns resolution)
2) If a connection is already established from an outbound connection then we allow an inbound connection.
3)All other connections that do not meet the above criteria are blocked.

iptables -A INPUT -i lo  -m state --state NEW -p udp --dport 53 -j ACCEPT

iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

iptables -A INPUT -m  state --state NEW,INVALID -j REJECT

Grsecurity On Desktop Is Simple

Some people find the idea of compiling their own kernel to be fairly daunting. And, to an extent, it is. There’s greater chance for issues to arise when you start handling things yourself if you aren’t careful. But the benefits are very significant.

I’ve been running a Grsecurity patched kernel for months with very few issues – most have been due to me messing around and ATI drivers having massive security flaws. Performance is not any worse that I can tell – I feel absolutely no ‘bog down’ in any way.

Running your kernel patched with Grsecurity is the number one best way to stay secure. Every single thing I’ve written about is made better when you run it with a secure kernel, and Grsecurity is the leader by a long shot when it comes to kernel security.

Actual compile time on my laptop takes about 2 hours. That’s actually not that bad – consider that it runs in the background, the system is fine and responsive while it’s going on, and it’ll easily be done by the time I wake up.

All of the troubleshooting will happen at the beginning, the first compile. After that it’s smooth sailing.

You get a kernel that’s considerably more secure and faster if you take the time to optimize it.

Here’s a guide to patch your Grsecurity kernel.

Explaining Chrome’s Linux Sandbox

Note: The documentation for Chrome’s Linux sandbox is lacking. This is my attempt to make sense of it and clarify how it works for users who may not want to sift through multiple docs on the subject. If I have misinterpreted, let me know, some of the docs are out of date and I may not have been informed.

Chrome is well known for its sandbox, which has held up incredibly well over the years – not a single in the wild attack against it. But on the Linux side of things it’s even more impressive, Chrome’s sandbox is immensely more powerful than on Windows. Though the architecture is similar, the mechanism is fairly different.

Chrome’s architecture is made up of multiple parts – on Linux there is a broker, your SetUID Sandbox process, and your tabs, renderer, plugins, and extensions (the Zygote processes).

The Chrome-Sandbox SUID Helper Binary launches when Chrome does, and sets up the sandbox environment. The sandbox environment is meant to be restrictive to the file system and other processes, attempting to isolate various Chrome parts (such as the renderer) from the system.

A sandboxed process is put inside a Chroot, a sort of a virtual file system (chroot = change root, it’s a new root). It basically gets its own file system to work with, an din this case, it’s not given any write access to the system. The limitations imposed on the process prevent it from escaping the chroot.

The sandboxed process is also provided a PID namespace (a way for a process to look like it’s standalone on the machine,  or among a subset of processes), denying it the ability to use ptrace() or kill() other processes. ptrace() in particular is dangerous as it allows processes to read or manipulate data in other processes. Sandboxed processes are unable to ptrace() each other as well (set to undumpable).

A network namespace is used as well in order to prevent sandboxed processes from connecting out – not much documentation on this.

The Broker process, which remains unrestricted by SUID, is what handles decisions about downloading files, writing to the disk, etc. It handles the dangerous stuff, and is unrestricted, but it is separated from the areas of the program that are most open to attack. Using an Apparmor profile will allow restriction even of the broker process. Otherwise it remains confined purely by DAC.

The next layer of restriction is provided by the Seccomp-BPF sandbox. Seccomp filters are something I’ve written about before. Their goal isn’t to protect the system from damage, like the SUID sandbox does, but to protect the system from further exploitation.

Seccomp-BPF works by restricting the system calls that programs can make. The implications of this are covered in this post. A quick summary is that a sandbox, or any form of access control, is only as powerful as the kernel. It is very often the case that, rather than trying to find issues with the sandbox itself, an attacker can simply go after the big buggy kernel running underneath it. An attack on the kernel allows for a full bypass of the sandbox.*

Seccomp works by restricting access to the kernel by filtering the ‘calls’ that can be made to it. The fewer calls a program can make the fewer ways it can exploit the system. Suddenly the kernel isn’t this massive glob of attack surface, it’s a much smaller are, with monitored interaction between it and the program.

Chrome on Windows had its sandbox broken at Pwn2Own by MWRLabs. It was, in fact, a local kernel vulnerable that allowed them to bypass the sandbox once they’d gained access to the renderer. Such an attack would be far more difficult on a Linux system with Seccomp enabled.

Overall the sandbox works by reducing the potential for damage and reducing the potential for local exploitation. Chrome is, as always, pouring work into their security. Their sandbox is very impressive, and I would love to see some research into breaking it.

There was a ‘partial reward’ for PinkiePie exploiting ChromeOS, but it was unreliable. No details have been released yet, quite unfortunately.

*Plug for Grsecurity here. See my guide for setting up a hardened Grsec kernel. Seccomp limits kernel attack surface, Grsecurity makes the entire kernel more difficult to exploit.

Hardening Ubuntu Linux

I’m going to keep some tips here for users looking to improve their security, when I update it I’ll tweet about it, so feel free to follow me @insanitybit. This is aimed at desktop users but naturally lots of it can apply to a Linux server. Some of this will be simple, trivial, and some of this will be quite a bit more difficult. I’m focusing specifically on Ubuntu but other distros will have similar features (replace Apparmor with SELinux). I will try to make this as comprehensive as possible, though I’m specifically avoiding items like Fail2Ban as it’s not really useful for users. You can consider this an extension of my ‘definitive guides‘ – The Definitive Guide For Securing Linux Ubuntu.

A lot of users believe that a distro such as Ubuntu will be so much more secure than Windows, purely through virtue of obscurity. As Linux popularity continues to grow you’ll see attackers begin to take notice. Just because attackers don’t care to hack Linux desktop systems does not by any means imply they aren’t capable of it, or ready to when it seems profitable.

Thankfully, Linux is really easy to secure. Despite some problems there are a lot of powerful projects that give users the power to secure themselves against many threats.

Securing Your Browser

First I’d like to start by linking to my guides for locking down Chrome and Firefox As a user your most exploitable area is your browser, it’s constantly taking in untrusted content, often over an insecure connection. I personally love Chrome’s Linux sandbox, but Firefox with NoScript is very powerful as well – I leave it to you to decide between the two based on your needs.

Enabling Ubuntu’s Firewall

Ubuntu comes with a firewall utility called UFW, but it isn’t enabled by default. The reason is that, by default, Ubuntu doesn’t have any open ports open (except for system services that are typically necessary for the average user). So is a Firewall strictly necessary? Well, if you’re behind a NAT router not so much, any open ports will expose you to local attacks, but you’re ‘hidden’ from the internet. Still, if you’re looking to secure your system you can simply run this command:

ufw enable

ufw default deny incoming

And it should prevent inbound access. You can create complex rules via iptables to restrict or relax your rules. You can also check out GUFW for a graphic interface to UFW. GUFW makes everything very easy to use.

You can use UFW/GUFW to create outbound rules for applications. Due to the amount that applications within a user ID can interfere with one another I do not feel that an outbound firewall is worthwhile for security, and it can be quite a bit of a pain. If you’re serious about setting up an outbound firewall I suggest you make strict use of user separation and apparmor, though even then the benefits are questionable (there is a reason programs like Comodo on Windows bundle their firewall components with strict HIPS software).

See this guide for further information on setting up firewalls. Courtesy of a very smart guy, Dangertux.

Run a Program As A Separate User

While the simplest way to restrict a program is AppArmor (see below) you can also make use of the native user/group Linux permissions in order to run an application as a different user. I’ve written a guide with Pidgin as the example. Separated programs will have less access to one another and they’ll live in a different user directory, with access only to that directory.

By separating a program to a new user we can also write more powerful firewall rules, as the program won’t be able to bypass an outbound rule as trivially.

For a risky program that doesn’t need to access other programs this may be a very viable option. For example, I run Xchat, which hasn’t been updated in about two years. For a program like this throwing as much security as possible at it isn’t a bad idea, since it doesn’t get patches, doesn’t use modern security techniques, and is internet facing.

Restricting DMESG

By default unprivileged users can read a lot of your systems logs. These logs can contain critical information for an attacker hoping to exploit your system further.

This is useful for debugging, but you’re not likely to have to do that. Running this command will prevent access by unprivileged users:

echo kernel.dmesg_restrict = 1 >> /etc/sysctl.conf

This feature is also included in the Grsecurity patch.

DNSCrypt

DNSCrypt is a DNS resolver that encrypts the content of your request between you and the first level resolver. It prevents an attacker from hijacking or viewing your DNS resolution and the program itself is hardened quite a lot.

For a guide to install.

For a guide to harden further.

Removing Attack Surface

One of the first steps to harden any operating system should always be disabling unnecessary programs/ services. Desktop operating systems don’t come “default secure” they come “default compatible” and that means meeting the needs of every person, generically. So while John may use his network printer Jane may not, but Jane’s system still comes with all of the attack surface necessary for network printing.

The network printing service is cupsd. It comes, by default, in an Apparmor profile, so it’s not like you should be incredibly worried about being exploited. And if you’re behind NAT you’re only exposed to local attacks. But, if you’re like me, you don’t print over a network and you have no need for this service. Are you likely to be attacked over it? Maybe, maybe not, but it’s not needed. So go ahead and remove that service.

You can check for programs listening on your system with the following command:

netstat -tulnp

Look up any services and carefully consider the benefit/ necessity of them. If you don’t need them or want them, remove them.

Another tip is to use checksec.sh. Run the following command: (You must first set the file as executable)

./checksec.sh –proc-all

It will provide you with a list of running services along with information about their security – whether they use NX, stack canaries, and if they’ve been compiled as Position Independent Executables (PIE). This may help you make a more informed decision about removing a service.

Mount /tmp With noexec,nodev,nosuid

Many programs require read/write access to /tmp but, for the most part, no programs actually need to be able to execute from there. Mounting this area with the noexec, nodev, nosuid can provide some level of security. Rather than creating a new partition for /tmp I find it’s just easier to use RAM (it expands as needed and doesn’t require partitioning , one benefit being a (potential) performance increase, though I wouldn’t bet on it.

Copy the following into your /etc/fstab file.

tmpfs /tmp tmpfs mode=1777,nosuid,nodev,noexec 0 0

If you want to create a new partition for /tmp you can find a guide online for that. It’s kinda a pain. The downside to running it in RAM is, obviously, you lose some RAM. If you want to limit the amount of RAM it can use (tmpfs expands as needed) you can change the line to (for 512M):

tmpfs /tmp tmpfs size=512M,mode=1777,nosuid,nodev,noexec 0 0

I recommend that if you follow the above you make use of AppArmor to improve the level of security this adds. If you use /tmp in RAM one benefit is that, in your AppArmor profiles, you should be able to remove map rules for some programs that map /tmp for performance reasons.

AppArmor

AppArmor is the Linux Security Module of choice for Ubuntu. It implements Mandatory Access Control on a per-process basis. It’s very simple to learn how to use AppArmor and I’ve written a guide. In the guide I provide tips for creating strong AppArmor profiles and avoiding potential pitfalls.

A program like Pidgin has a lot of access to your system. It runs as the same user as many other programs on your system and therefor is granted a fair amount of control over them. It can read many areas of the system that it doesn’t need to read, it can write to quite a few too. AppArmor restricts it to only the resources it needs, making both remote and local privilege exploits more difficult to pull off.

I’ve written a few very strict AppArmor profiles myself that you’re welcome to use as a starting point. [Xchat][Pulseaudio] [Java]

32bit users will have to adjust as needed, though it should be as simple as replacing the x86_64 with i386 (I’ll add variables for this at some point so you won’t have to).

Every internet facing program deserves an AppArmor profiles. It’s the simplest way to implement least privilege on a per application basis.

PaX and Grsecurity

PaX and Grsecurity are patches for the Linux kernel (the Grsecurity patch contains both, don’t just use PaX). PaX and Grsecurity have been at the forefront of security for more than a decade, bringing some of the most important security mitigation techniques to systems today, such as Address Space Layout Randomization (ASLR). ASLR is a great example of a mitigation technique that doesn’t have a great implementation in typical vanilla systems. The ASLR in your average distro, like Ubuntu, introduces far less entropy into the system, which degrades its use. The ASLR is also missing critical features, such as brute force deterrence, among others. PaX and Grsecurity bring these features and many many others to Linux. No operating system has as complete ASLR as PaX and, really, nothing else compares.

Not all of these features are compatible for desktop users, or even necessary, but a number of them will work on an Ubuntu desktop. You can see my guide for patching and compiling a Grsecurity Linux kernel, with notes about compatibility issues for desktop users.

Many of these security features directly relate to desktop security. Many applications and services use chroot to run programs in a separate environment. Chroot is incapable of restricting programs that can run as root, multiple bypasses are possible. Chrome is one such program, along with many other services (like avahi-daemon), so using the chroot hardening features of Grsecurity will provide a considerably more secure environment.

PaX and Grsecurity can be implemented with very little performance overhead, and very few stability issues if configured properly. If you’re really looking to secure your Linux system and you’re willing to take the time to compile it you should give it a try.

Learn how to compile your own Grsecurity Linux kernel here.

Patching

None of the above will make up for a system that is out of date and unpatched. If you’re using an older kernel and userland applications an attacker will be able to chain together enough exploits to bypass any restrictions/ measures you’ve taken, no matter how powerful. Make sure to stay up to date for all applications.

You can push patch time further by hardening the system – time to develop an exploit for a hardened system is longer. This does not mean you can postpone indefinitely, it just buys you time to test patches and improve your patch management.

Something To Keep In Mind

This all works best in conjunction. Grsecurity and PaX are honestly the best security software there is, in my opinion, but they can’t make up for a completely insecure userland. If you’re running programs that opt out or don’t make use of modern technology there’s only so much they can do. It’s very unfortunate but, even on 64bit, Ubuntu ships with a lot of services not using Position Independent Executable code – at this point it’s necessary to harden the programs in other ways.

And the same goes both ways. If you’re not using Grsecurity and PaX then your kernel is less secure, meaning that even if you harden a userland application with apparmor an attacker will have a much easier time exploiting the kernel and escaping the profile.

If you’re annoyed about your distro coming with insecure settings email them about it. You can reach Canonical:

http://www.canonical.com/about-canonical/contact

 you have suggestions for canonical.com or ubuntu.com, please email us atwebmaster@canonical.com or webmaster@ubuntu.com.

And if you have any suggestions for this guide please let me know in a comment. I’ll happily include any relevant information.

Follow me @insanitybit for updates and more articles like this.

Speeding Up Unity On Ubuntu With ATI Cards

I use Ubuntu 12.10 with Unity and I run a mid range ATI 5000 series GPU. Performance was surprisingly good in 12.10 after a fresh install (upgrade made performance horrible) but while playing Flash/HTML5 video things slowed down considerably, and using Super + W (expose) was much slower.

I searched around for some quick tips and found two that have apparently improved things significantly.

sudo apt-get install compizconfig-settings-manager

Then go to the CCSM and the OpenGL plugin and disable “Sync to Vblank”.

Go back to CCSM and then the Composite plugin. This time disable the “Check refresh rate”.

Expose is now much quicker/ smoother. Noticeably so – even while I’m playing video in Chrome. The difference is like night and day – I can reload pages/ tabs alongside the video and move windows around and it’s all smooth.

Make sure you’re on the latest ATI drivers. Due to Valve pushing for better Linux drivers the most recent versions (12.8/12.9) feature vastly improved performance.