tame(1), like nice(1) but for permissions
I'm not sure if this makes sense, since tame(2) was designed to operate on processes after they have already been initialized, and this would set the allowed operations before initializing the process. It's a fairly simple change to get the basics working as shown here, but it's currently not very useful as more complex programs generally can't start even if given all current tame(2) permissions. I mostly did this to get more experience working in the kernel, not because I think it is a good idea, but I welcome feedback all the same. First the manual, followed by the code, then the kernel and tame(2) manpage diff. Thanks, Jeremy TAME(1) General Commands ManualTAME(1) NAME tame - restrict system operations for process SYNOPSIS tame [-aCcdghIiRSptuw] utility [argument ...] DESCRIPTION tame restricts system operations using the tame(2) system call, then executes the utility with the given arguments. If the utility attempts to perform an operation which was not permitted, it will be killed by the system with SIGKILL. By default, tame restricts almost all system operations for the executed process, allowing only the execution of processes (TAME_EXEC), use of stdio (TAME_STDIO), and reading the file system (TAME_RPATH). All flags with the exception of -h, -R, and -S allow additional system operations. The options that allow additional system operations are as follows, with the tame(2) option that they enable: -a TAME_ABORT -C TAME_CMSG -c TAME_CPATH -d TAME_DNS -g TAME_GETPW -I TAME_IOCTL -i TAME_INET -p TAME_PROC -t TAME_TMPPATH -u TAME_UNIX -w TAME_WPATH The following options restrict system operations that are allowed by default: -R TAME_RW -r TAME_RPATH The -h option displays the usage. If the -r option is used, utilty must be the full path to the utility, tame will no longer search the PATH to find it, as it will have already restricted the permissions that would allow that. EXIT STATUS The tame utility exits with one of the following values: 125 An error occurred. 126 The utility was not found or could not be invoked. Otherwise, the exit status of tame shall be that of utility. EXAMPLES Only allow overwriting files that already exist, do not allow creating new files: $ tame -w cp from to SEE ALSO tame(2) HISTORY The tame() system call appeared in OpenBSD 5.8. $Mdocdate: $ OpenBSD 5.8 tame.c: /* $OpenBSD: $ */ /* * Copyright (c) 2015 Jeremy Evans jer...@openbsd.org * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include err.h #include stdio.h #include stdlib.h #include sys/tame.h #include unistd.h __dead void usage(int); int main(int argc, char *argv[]) { char ch; char *file; /* TAME_RPATH needed to find process to execute * TAME_EXEC needed to execute the process * TAME_STDIO needed by almost all processes */ int tame_flags = TAME_RPATH | TAME_STDIO | TAME_EXEC; while ((ch = getopt(argc, argv, aCcdghIiRrptuw)) != -1) switch (ch) { case 'a': tame_flags |= TAME_ABORT; break; case 'C': tame_flags |= TAME_CMSG; break; case 'c': tame_flags |= TAME_CPATH; break; case 'd': tame_flags |= TAME_DNS; break; case 'g': tame_flags |= TAME_GETPW; break; case 'I': tame_flags |= TAME_IOCTL; break; case 'i': tame_flags |= TAME_INET; break; case 'p': tame_flags |= TAME_PROC; break;
Re: tame(1), like nice(1) but for permissions
Hi I'm not sure I can think of many uses for this, tame is not something you are intended to just apply blindly, do you have any use cases? I think the -aCcdghIiRSptuw approach is a bad idea and it would be better to do it with named flags like -o abort,cmsg,cpath. Maybe take a look at getsubopt(3), although I don't know if that API is in vogue anymore. Also adding TAME_EXEC seems like a different change entirely? On Mon, Jul 20, 2015 at 01:00:00AM -0700, Jeremy Evans wrote: I'm not sure if this makes sense, since tame(2) was designed to operate on processes after they have already been initialized, and this would set the allowed operations before initializing the process. It's a fairly simple change to get the basics working as shown here, but it's currently not very useful as more complex programs generally can't start even if given all current tame(2) permissions. I mostly did this to get more experience working in the kernel, not because I think it is a good idea, but I welcome feedback all the same. First the manual, followed by the code, then the kernel and tame(2) manpage diff. Thanks, Jeremy TAME(1) General Commands ManualTAME(1) NAME tame - restrict system operations for process SYNOPSIS tame [-aCcdghIiRSptuw] utility [argument ...] DESCRIPTION tame restricts system operations using the tame(2) system call, then executes the utility with the given arguments. If the utility attempts to perform an operation which was not permitted, it will be killed by the system with SIGKILL. By default, tame restricts almost all system operations for the executed process, allowing only the execution of processes (TAME_EXEC), use of stdio (TAME_STDIO), and reading the file system (TAME_RPATH). All flags with the exception of -h, -R, and -S allow additional system operations. The options that allow additional system operations are as follows, with the tame(2) option that they enable: -a TAME_ABORT -C TAME_CMSG -c TAME_CPATH -d TAME_DNS -g TAME_GETPW -I TAME_IOCTL -i TAME_INET -p TAME_PROC -t TAME_TMPPATH -u TAME_UNIX -w TAME_WPATH The following options restrict system operations that are allowed by default: -R TAME_RW -r TAME_RPATH The -h option displays the usage. If the -r option is used, utilty must be the full path to the utility, tame will no longer search the PATH to find it, as it will have already restricted the permissions that would allow that. EXIT STATUS The tame utility exits with one of the following values: 125 An error occurred. 126 The utility was not found or could not be invoked. Otherwise, the exit status of tame shall be that of utility. EXAMPLES Only allow overwriting files that already exist, do not allow creating new files: $ tame -w cp from to SEE ALSO tame(2) HISTORY The tame() system call appeared in OpenBSD 5.8. $Mdocdate: $ OpenBSD 5.8 tame.c: /*$OpenBSD: $ */ /* * Copyright (c) 2015 Jeremy Evans jer...@openbsd.org * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include err.h #include stdio.h #include stdlib.h #include sys/tame.h #include unistd.h __dead void usage(int); int main(int argc, char *argv[]) { char ch; char *file; /* TAME_RPATH needed to find process to execute * TAME_EXEC needed to execute the process * TAME_STDIO needed by almost all processes */ int tame_flags = TAME_RPATH | TAME_STDIO | TAME_EXEC; while ((ch = getopt(argc, argv, aCcdghIiRrptuw)) != -1) switch (ch) { case 'a': tame_flags |= TAME_ABORT; break; case 'C': tame_flags |= TAME_CMSG; break; case 'c':
Re: tame(1), like nice(1) but for permissions
On Mon, Jul 20, 2015 at 10:41:08AM -0600, Theo de Raadt wrote: On Mon, Jul 20, 2015 at 12:04:43PM -0400, Ted Unangst wrote: chroot is probably the best comparision. yes, we provide a chroot(1), but There is no chroot(1). :p practically nothing uses it. everything is instead calling chroot(2) on its own. the things that do use chroot(1) are doing so for specialized namespace reasons, not for sandboxing. I have a huge counter-example: dpb. Specifically, chroot(8) does the nice usercontext thingies that would be cumbersome to do from perl. chroot was only used as a partial example. I have the same concerns with tame(1). First, it is very premature. Secondly, TAME_EXEC is a very nasty semantic. Most importantly the purpose of tame is to allow a programmer to seperate their initial-setup from the main-loop processing. By tagging the unix feature-set into a simple effect classifications, it also guides the programming of general purpose unix tools, guiding them towards privdrop, privsep; or if they have no specific priv-slit happening, at minimum it constraints most to files-only or network-only behaviours. From the outside, a regular user is not going to know the system features and semantics that a program uses, not in a detailed fashion. tame -a firefox doesn't work. Is tame broken? We don't need that kind of grief. Sorry, should have made things clearer. I just meant that chroot was a bad comparison. I can't see any sane use of a tame(1) at the moment.
Re: tame(1), like nice(1) but for permissions
On 07/20 09:36, Nicholas Marriott wrote: Hi I'm not sure I can think of many uses for this, tame is not something you are intended to just apply blindly, do you have any use cases? Well, there is the example in the man page. :) But no, currently it's not very useful, as more complex programs such as sh(1) or perl(1) won't start even if given all current tame(2) permissions. For this to be useful, you'd need to give TAME_EXEC additional permissions such that you could do `tame -tp sh`, and get a sh that could execute processes, but not write to the file system or do network access. And like I said originally, I'm not sure this is a good idea. It was just a way for me to get more kernel experience. I think the -aCcdghIiRSptuw approach is a bad idea and it would be better to do it with named flags like -o abort,cmsg,cpath. Maybe take a look at getsubopt(3), although I don't know if that API is in vogue anymore. If this is worthy of more work, the command line options can certainly be changed. I just used getopt(3) since it seemed like the easiest way to handle it. Also adding TAME_EXEC seems like a different change entirely? Without TAME_EXEC, you can't call execve(2) to create another process. There currently isn't a tame(2) permission that allows execing, one had to be added. Thanks, Jeremy
Re: tame(1), like nice(1) but for permissions
Sorry, should have made things clearer. I just meant that chroot was a bad comparison. I can't see any sane use of a tame(1) at the moment. No, no no, Ted's comments are completely valid. You cannot replace the narrow chroot calls in the privsep daemons with chroot(8) run externally. Any attempts to do so would degrade security. Same here with tame. Same with your pkg building tools.
Re: tame(1), like nice(1) but for permissions
Jeremy Evans wrote: If this is worthy of more work, the command line options can certainly be changed. I just used getopt(3) since it seemed like the easiest way to handle it. I talked with theo about this some. I'd say it's probably too early, and may lead us down a weird path, where tame has to record all sorts of state and watch for certain milestones to be reached. that logic is better kept in the program. currently, the tame model is that you modify the program as necessary to work best with tame. if you're doing that, add the tame calls you want. as you noticed, programs not expecting to work with tame require very permissive options and may not work even so. chroot is probably the best comparision. yes, we provide a chroot(1), but practically nothing uses it. everything is instead calling chroot(2) on its own. the things that do use chroot(1) are doing so for specialized namespace reasons, not for sandboxing.
Re: tame(1), like nice(1) but for permissions
On Mon, Jul 20, 2015 at 12:04:43PM -0400, Ted Unangst wrote: chroot is probably the best comparision. yes, we provide a chroot(1), but There is no chroot(1). :p practically nothing uses it. everything is instead calling chroot(2) on its own. the things that do use chroot(1) are doing so for specialized namespace reasons, not for sandboxing. I have a huge counter-example: dpb. Specifically, chroot(8) does the nice usercontext thingies that would be cumbersome to do from perl. chroot was only used as a partial example. I have the same concerns with tame(1). First, it is very premature. Secondly, TAME_EXEC is a very nasty semantic. Most importantly the purpose of tame is to allow a programmer to seperate their initial-setup from the main-loop processing. By tagging the unix feature-set into a simple effect classifications, it also guides the programming of general purpose unix tools, guiding them towards privdrop, privsep; or if they have no specific priv-slit happening, at minimum it constraints most to files-only or network-only behaviours. From the outside, a regular user is not going to know the system features and semantics that a program uses, not in a detailed fashion. tame -a firefox doesn't work. Is tame broken? We don't need that kind of grief.
Re: tame(1), like nice(1) but for permissions
On Mon, Jul 20, 2015 at 12:04:43PM -0400, Ted Unangst wrote: chroot is probably the best comparision. yes, we provide a chroot(1), but There is no chroot(1). :p practically nothing uses it. everything is instead calling chroot(2) on its own. the things that do use chroot(1) are doing so for specialized namespace reasons, not for sandboxing. I have a huge counter-example: dpb. Specifically, chroot(8) does the nice usercontext thingies that would be cumbersome to do from perl.