2011-08-02 17:58:07 +00:00
|
|
|
#define _GNU_SOURCE
|
2010-06-10 20:35:55 +00:00
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <sched.h>
|
2011-08-03 19:09:22 +00:00
|
|
|
#include <libcgroup.h>
|
2010-06-10 20:35:55 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
2011-08-03 19:09:22 +00:00
|
|
|
#include <regex.h>
|
2010-06-10 20:35:55 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <cap-ng.h>
|
|
|
|
#include <getopt.h> /* for getopt_long() form of getopt() */
|
|
|
|
#include <limits.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <selinux/selinux.h>
|
|
|
|
#include <selinux/context.h> /* for context-mangling functions */
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#ifdef USE_NLS
|
|
|
|
#include <locale.h> /* for setlocale() */
|
|
|
|
#include <libintl.h> /* for gettext() */
|
|
|
|
#define _(msgid) gettext (msgid)
|
|
|
|
#else
|
|
|
|
#define _(msgid) (msgid)
|
|
|
|
#endif
|
|
|
|
|
Author: Steve Lawrence
Email: slawrence@tresys.com
Subject: Updated sandbox patch.
Date: Mon, 07 Jun 2010 17:53:41 -0400
On Thu, 2010-05-27 at 08:57 -0400, Daniel J Walsh wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 05/26/2010 04:06 PM, Steve Lawrence wrote:
> > On Wed, 2010-05-19 at 15:59 -0400, Daniel J Walsh wrote:
> > Fixed patch that handles Spaces in homedir.
>
> > The following patch makes a few updates the the sandbox patch, though I
> > have a question:
>
> > Is the sandbox.init script needed anymore? It looks like seunshare was
> > changed to now bind mount and make private the necessary directories.
> > The only thing that seems missing is making root rshared. Also, if the
> > init script is obsolete, do the mounts also need the MS_REC flag for
> > recursive bind/private like they are mounted in the init script? e.g.
>
> The init script is needed for the xguest package/more specifically
> pam_namespace, but also needed for
> mount --make-rshared /
>
> Whether the init script belongs in policycoreutils is questionable though.
>
>
> > mount(dst, dst, NULL, (MS_BIND | MS_REC), NULL)
> > mount(dst, dst, NULL, (MS_PRIVATE | MS_REC), NULL)
>
> We probably should add these. Although it is not likely.
>
> > Changes the following patch makes:
>
> > sandbox.py
> > - Removes unused 'import commands'
> > - Fixes the chcon function, and replaces the deprecated os.path.walk
> > with os.walk. I think this way is a bit easier to read too.
>
> I think chcon should be added to libselinux python bindings and then
> leave the recursive flag. (restorecon is currently in python bindings._
>
> > - Removes the 'yum install seunshare' message. This tool is not specific
> > to RPM based distros.
>
> People are using seunshare without X now that I have added the -M flag.
> So I will move it from the -gui package to the base package with
> sandbox and then this should not be necessary.
> > - Remove try/except around -I include to be consistent with the -i
> > option. If we can't include a file, then this should bail, no matter
> > if it's being included via -i or -I.
>
> Ok, I was thinking you could list a whole bunch of files in the -I case
> and if one does not exist, allow it to continue. But I don't really care.
> > - Fix homedir/tmpdir typo in chcon call
>
> > sandbox.init (maybe obsoleted?)
> > - Fix restart so it stops and starts
> > - unmount the bind mounts when stopped
> I doubt this will work. Two many locks in /tmp /home
> > - Abort with failure if any mounts fail
>
> > seunshare.c
> > - Define the mount flag MS_PRIVATE if it isn't already. The flag is only
> > defined in the latest glibc but has been in the kernel since 2005.
> > - Simplify an if-statment. Also, I'm not sure the purpose of the
> > strncmmp in that conditional, so maybe I've oversimplified.
> This is wrong. The problem comes about when you mount within the same
> directory.
>
> seunshare -t /home/dwalsh/sanbox/tmp -h /home/dwalsh/sandbox/home ...
>
> seunshare -t /tmp/sandbox/tmp -h /tmp/sandbox/home
>
> If you do not have the check one of the above will fail.
>
> In the first example if Homedir is mounted first,
> /home/dwalsh/sanbox/tmp will no longer exist when seunshare attempts to
> mount it on /tmp.
>
> Similarly, if /tmp is mounted first in the second example.
> /tmp/sandbox/home will no longer exist.
>
> You have to check to make sure one of the directories is not included in
> the other.
>
> It seems
> > like maybe an error should be thrown if tmpdir_s == pw_dir or
> > homedir_s == "/tmp", but maybe I'm missing something.
>
> See above.
>
> I was blowing up because I use
>
> ~/sandbox/tmp and ~/sandbox/home for my mountpoints.
<snip>
Below is an updated patch that makes a few changes the the latest
Sandbox Patch [1]. This requires the chcon patch [2].
Changes this patch makes:
sandbox.py
- Remove unused 'import commands'
- Uses new chcon method in libselinux [2]
- Removes the 'yum install seunshare' message
- Converts an IOError to a string for printing a warning if a file
listed in -I does not exist
sandbox.init
- Print the standard Starting/Stoping messages with the appropriate
OK/FAIL
- Abort with failure if any mounts fail
seunshare.c
- Add the MS_REC flag during mounts to perform recursive mounts
- Define the mount flags MS_PRIVATE and MS_REC if they aren't already.
The flags are only defined in the latest glibc but have been in the
kernel since 2005.
- Calls realpath(3) on tmpdir_s and homedir_s. If relative paths are
used, it wouldn't correctly detect that tmpdir is inside homedir and
change the mount order. This fixes that.
[1] http://marc.info/?l=selinux&m=127429948731841&w=2
[2] http://marc.info/?l=selinux&m=127594712200878&w=2
Signed-off-by: Chad Sellers <csellers@tresys.com>
2010-06-10 20:37:59 +00:00
|
|
|
#ifndef MS_REC
|
|
|
|
#define MS_REC 1<<14
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef MS_PRIVATE
|
|
|
|
#define MS_PRIVATE 1<<18
|
|
|
|
#endif
|
|
|
|
|
2011-08-03 19:09:22 +00:00
|
|
|
#define BUF_SIZE 1024
|
2011-08-03 20:23:12 +00:00
|
|
|
#define DEFAULT_PATH "/usr/bin:/bin"
|
2011-08-03 19:09:22 +00:00
|
|
|
#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [ -c ] [ -t tmpdir ] [ -h homedir ] [ -Z CONTEXT ] -- executable [args] ")
|
2011-08-03 20:23:12 +00:00
|
|
|
|
|
|
|
static int verbose = 0;
|
|
|
|
|
2011-06-13 17:24:38 +00:00
|
|
|
static capng_select_t cap_set = CAPNG_SELECT_BOTH;
|
|
|
|
|
2010-06-10 20:35:55 +00:00
|
|
|
/**
|
2011-08-05 17:33:35 +00:00
|
|
|
* This function will drop all capabilities.
|
2010-06-10 20:35:55 +00:00
|
|
|
*/
|
2011-08-05 17:33:35 +00:00
|
|
|
static int drop_caps()
|
2010-06-10 20:35:55 +00:00
|
|
|
{
|
2011-06-13 17:24:38 +00:00
|
|
|
if (capng_have_capabilities(cap_set) == CAPNG_NONE)
|
2011-08-05 17:33:35 +00:00
|
|
|
return 0;
|
2011-06-13 17:24:38 +00:00
|
|
|
capng_clear(cap_set);
|
|
|
|
if (capng_lock() == -1 || capng_apply(cap_set) == -1) {
|
2011-08-05 17:33:35 +00:00
|
|
|
fprintf(stderr, _("Failed to drop all capabilities\n"));
|
2010-06-10 20:35:55 +00:00
|
|
|
return -1;
|
2011-08-05 17:33:35 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function will drop all privileges.
|
|
|
|
*/
|
|
|
|
static int drop_privs(uid_t uid)
|
|
|
|
{
|
|
|
|
if (drop_caps() == -1 || setresuid(uid, uid, uid) == -1) {
|
|
|
|
fprintf(stderr, _("Failed to drop privileges\n"));
|
2010-06-10 20:35:55 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2011-08-05 17:33:35 +00:00
|
|
|
return 0;
|
2010-06-10 20:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-08-03 18:27:32 +00:00
|
|
|
* Take care of any signal setup.
|
2010-06-10 20:35:55 +00:00
|
|
|
*/
|
|
|
|
static int set_signal_handles(void)
|
|
|
|
{
|
|
|
|
sigset_t empty;
|
|
|
|
|
|
|
|
/* Empty the signal mask in case someone is blocking a signal */
|
|
|
|
if (sigemptyset(&empty)) {
|
|
|
|
fprintf(stderr, "Unable to obtain empty signal set\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void)sigprocmask(SIG_SETMASK, &empty, NULL);
|
|
|
|
|
|
|
|
/* Terminate on SIGHUP. */
|
|
|
|
if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
|
|
|
|
perror("Unable to set SIGHUP handler");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-05 18:06:34 +00:00
|
|
|
#define status_to_retval(status,retval) do { \
|
|
|
|
if ((status) == -1) \
|
|
|
|
retval = -1; \
|
|
|
|
else if (WIFEXITED((status))) \
|
|
|
|
retval = WEXITSTATUS((status)); \
|
|
|
|
else if (WIFSIGNALED((status))) \
|
|
|
|
retval = 128 + WTERMSIG((status)); \
|
|
|
|
else \
|
|
|
|
retval = -1; \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Spawn external command using system() with dropped privileges.
|
|
|
|
* TODO: avoid system() and use exec*() instead
|
|
|
|
*/
|
|
|
|
static int spawn_command(const char *cmd, uid_t uid){
|
|
|
|
int child;
|
|
|
|
int status = -1;
|
|
|
|
|
|
|
|
if (verbose > 1)
|
|
|
|
printf("spawn_command: %s\n", cmd);
|
|
|
|
|
|
|
|
child = fork();
|
|
|
|
if (child == -1) {
|
|
|
|
perror(_("Unable to fork"));
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (child == 0) {
|
|
|
|
if (drop_privs(uid) != 0) exit(-1);
|
|
|
|
|
|
|
|
status = system(cmd);
|
|
|
|
status_to_retval(status, status);
|
|
|
|
exit(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
waitpid(child, &status, 0);
|
|
|
|
status_to_retval(status, status);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2010-06-10 20:35:55 +00:00
|
|
|
/**
|
|
|
|
* This function makes sure the mounted directory is owned by the user executing
|
|
|
|
* seunshare.
|
|
|
|
* If so, it returns 0. If it can not figure this out or they are different, it returns -1.
|
|
|
|
*/
|
|
|
|
static int verify_mount(const char *mntdir, struct passwd *pwd) {
|
|
|
|
struct stat sb;
|
|
|
|
if (stat(mntdir, &sb) == -1) {
|
|
|
|
fprintf(stderr, _("Invalid mount point %s: %s\n"), mntdir, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (sb.st_uid != pwd->pw_uid) {
|
|
|
|
errno = EPERM;
|
|
|
|
syslog(LOG_AUTHPRIV | LOG_ALERT, "%s attempted to mount an invalid directory, %s", pwd->pw_name, mntdir);
|
|
|
|
perror(_("Invalid mount point, reporting to administrator"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-05 18:36:29 +00:00
|
|
|
/**
|
|
|
|
* Check file/directory ownership, struct stat * must be passed to the
|
|
|
|
* functions.
|
|
|
|
*/
|
|
|
|
static int check_owner_uid(uid_t uid, const char *file, struct stat *st) {
|
|
|
|
if (S_ISLNK(st->st_mode)) {
|
|
|
|
fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (st->st_uid != uid) {
|
|
|
|
fprintf(stderr, _("Error: %s not owned by UID %d\n"), file, uid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_owner_gid(gid_t gid, const char *file, struct stat *st) {
|
|
|
|
if (S_ISLNK(st->st_mode)) {
|
|
|
|
fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (st->st_gid != gid) {
|
|
|
|
fprintf(stderr, _("Error: %s not owned by GID %d\n"), file, gid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define equal_stats(one,two) \
|
|
|
|
((one)->st_dev == (two)->st_dev && (one)->st_ino == (two)->st_ino && \
|
|
|
|
(one)->st_uid == (two)->st_uid && (one)->st_gid == (two)->st_gid && \
|
|
|
|
(one)->st_mode == (two)->st_mode)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sanity check specified directory. Store stat info for future comparison, or
|
|
|
|
* compare with previously saved info to detect replaced directories.
|
|
|
|
* Note: This function does not perform owner checks.
|
|
|
|
*/
|
|
|
|
static int verify_directory(const char *dir, struct stat *st_in, struct stat *st_out) {
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
if (st_out == NULL) st_out = &sb;
|
|
|
|
|
|
|
|
if (lstat(dir, st_out) == -1) {
|
|
|
|
fprintf(stderr, _("Failed to stat %s: %s\n"), dir, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (! S_ISDIR(st_out->st_mode)) {
|
|
|
|
fprintf(stderr, _("Error: %s is not a directory: %s\n"), dir, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (st_in && !equal_stats(st_in, st_out)) {
|
|
|
|
fprintf(stderr, _("Error: %s was replaced by a different directory\n"), dir);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-10 20:35:55 +00:00
|
|
|
/**
|
|
|
|
* This function checks to see if the shell is known in /etc/shells.
|
|
|
|
* If so, it returns 0. On error or illegal shell, it returns -1.
|
|
|
|
*/
|
|
|
|
static int verify_shell(const char *shell_name)
|
|
|
|
{
|
|
|
|
int rc = -1;
|
|
|
|
const char *buf;
|
|
|
|
|
|
|
|
if (!(shell_name && shell_name[0]))
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
while ((buf = getusershell()) != NULL) {
|
|
|
|
/* ignore comments */
|
|
|
|
if (*buf == '#')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* check the shell skipping newline char */
|
|
|
|
if (!strcmp(shell_name, buf)) {
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
endusershell();
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int seunshare_mount(const char *src, const char *dst, struct passwd *pwd) {
|
|
|
|
if (verbose)
|
|
|
|
printf("Mount %s on %s\n", src, dst);
|
Author: Steve Lawrence
Email: slawrence@tresys.com
Subject: Updated sandbox patch.
Date: Mon, 07 Jun 2010 17:53:41 -0400
On Thu, 2010-05-27 at 08:57 -0400, Daniel J Walsh wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 05/26/2010 04:06 PM, Steve Lawrence wrote:
> > On Wed, 2010-05-19 at 15:59 -0400, Daniel J Walsh wrote:
> > Fixed patch that handles Spaces in homedir.
>
> > The following patch makes a few updates the the sandbox patch, though I
> > have a question:
>
> > Is the sandbox.init script needed anymore? It looks like seunshare was
> > changed to now bind mount and make private the necessary directories.
> > The only thing that seems missing is making root rshared. Also, if the
> > init script is obsolete, do the mounts also need the MS_REC flag for
> > recursive bind/private like they are mounted in the init script? e.g.
>
> The init script is needed for the xguest package/more specifically
> pam_namespace, but also needed for
> mount --make-rshared /
>
> Whether the init script belongs in policycoreutils is questionable though.
>
>
> > mount(dst, dst, NULL, (MS_BIND | MS_REC), NULL)
> > mount(dst, dst, NULL, (MS_PRIVATE | MS_REC), NULL)
>
> We probably should add these. Although it is not likely.
>
> > Changes the following patch makes:
>
> > sandbox.py
> > - Removes unused 'import commands'
> > - Fixes the chcon function, and replaces the deprecated os.path.walk
> > with os.walk. I think this way is a bit easier to read too.
>
> I think chcon should be added to libselinux python bindings and then
> leave the recursive flag. (restorecon is currently in python bindings._
>
> > - Removes the 'yum install seunshare' message. This tool is not specific
> > to RPM based distros.
>
> People are using seunshare without X now that I have added the -M flag.
> So I will move it from the -gui package to the base package with
> sandbox and then this should not be necessary.
> > - Remove try/except around -I include to be consistent with the -i
> > option. If we can't include a file, then this should bail, no matter
> > if it's being included via -i or -I.
>
> Ok, I was thinking you could list a whole bunch of files in the -I case
> and if one does not exist, allow it to continue. But I don't really care.
> > - Fix homedir/tmpdir typo in chcon call
>
> > sandbox.init (maybe obsoleted?)
> > - Fix restart so it stops and starts
> > - unmount the bind mounts when stopped
> I doubt this will work. Two many locks in /tmp /home
> > - Abort with failure if any mounts fail
>
> > seunshare.c
> > - Define the mount flag MS_PRIVATE if it isn't already. The flag is only
> > defined in the latest glibc but has been in the kernel since 2005.
> > - Simplify an if-statment. Also, I'm not sure the purpose of the
> > strncmmp in that conditional, so maybe I've oversimplified.
> This is wrong. The problem comes about when you mount within the same
> directory.
>
> seunshare -t /home/dwalsh/sanbox/tmp -h /home/dwalsh/sandbox/home ...
>
> seunshare -t /tmp/sandbox/tmp -h /tmp/sandbox/home
>
> If you do not have the check one of the above will fail.
>
> In the first example if Homedir is mounted first,
> /home/dwalsh/sanbox/tmp will no longer exist when seunshare attempts to
> mount it on /tmp.
>
> Similarly, if /tmp is mounted first in the second example.
> /tmp/sandbox/home will no longer exist.
>
> You have to check to make sure one of the directories is not included in
> the other.
>
> It seems
> > like maybe an error should be thrown if tmpdir_s == pw_dir or
> > homedir_s == "/tmp", but maybe I'm missing something.
>
> See above.
>
> I was blowing up because I use
>
> ~/sandbox/tmp and ~/sandbox/home for my mountpoints.
<snip>
Below is an updated patch that makes a few changes the the latest
Sandbox Patch [1]. This requires the chcon patch [2].
Changes this patch makes:
sandbox.py
- Remove unused 'import commands'
- Uses new chcon method in libselinux [2]
- Removes the 'yum install seunshare' message
- Converts an IOError to a string for printing a warning if a file
listed in -I does not exist
sandbox.init
- Print the standard Starting/Stoping messages with the appropriate
OK/FAIL
- Abort with failure if any mounts fail
seunshare.c
- Add the MS_REC flag during mounts to perform recursive mounts
- Define the mount flags MS_PRIVATE and MS_REC if they aren't already.
The flags are only defined in the latest glibc but have been in the
kernel since 2005.
- Calls realpath(3) on tmpdir_s and homedir_s. If relative paths are
used, it wouldn't correctly detect that tmpdir is inside homedir and
change the mount order. This fixes that.
[1] http://marc.info/?l=selinux&m=127429948731841&w=2
[2] http://marc.info/?l=selinux&m=127594712200878&w=2
Signed-off-by: Chad Sellers <csellers@tresys.com>
2010-06-10 20:37:59 +00:00
|
|
|
if (mount(dst, dst, NULL, MS_BIND | MS_REC, NULL) < 0) {
|
2010-06-10 20:35:55 +00:00
|
|
|
fprintf(stderr, _("Failed to mount %s on %s: %s\n"), dst, dst, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Author: Steve Lawrence
Email: slawrence@tresys.com
Subject: Updated sandbox patch.
Date: Mon, 07 Jun 2010 17:53:41 -0400
On Thu, 2010-05-27 at 08:57 -0400, Daniel J Walsh wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 05/26/2010 04:06 PM, Steve Lawrence wrote:
> > On Wed, 2010-05-19 at 15:59 -0400, Daniel J Walsh wrote:
> > Fixed patch that handles Spaces in homedir.
>
> > The following patch makes a few updates the the sandbox patch, though I
> > have a question:
>
> > Is the sandbox.init script needed anymore? It looks like seunshare was
> > changed to now bind mount and make private the necessary directories.
> > The only thing that seems missing is making root rshared. Also, if the
> > init script is obsolete, do the mounts also need the MS_REC flag for
> > recursive bind/private like they are mounted in the init script? e.g.
>
> The init script is needed for the xguest package/more specifically
> pam_namespace, but also needed for
> mount --make-rshared /
>
> Whether the init script belongs in policycoreutils is questionable though.
>
>
> > mount(dst, dst, NULL, (MS_BIND | MS_REC), NULL)
> > mount(dst, dst, NULL, (MS_PRIVATE | MS_REC), NULL)
>
> We probably should add these. Although it is not likely.
>
> > Changes the following patch makes:
>
> > sandbox.py
> > - Removes unused 'import commands'
> > - Fixes the chcon function, and replaces the deprecated os.path.walk
> > with os.walk. I think this way is a bit easier to read too.
>
> I think chcon should be added to libselinux python bindings and then
> leave the recursive flag. (restorecon is currently in python bindings._
>
> > - Removes the 'yum install seunshare' message. This tool is not specific
> > to RPM based distros.
>
> People are using seunshare without X now that I have added the -M flag.
> So I will move it from the -gui package to the base package with
> sandbox and then this should not be necessary.
> > - Remove try/except around -I include to be consistent with the -i
> > option. If we can't include a file, then this should bail, no matter
> > if it's being included via -i or -I.
>
> Ok, I was thinking you could list a whole bunch of files in the -I case
> and if one does not exist, allow it to continue. But I don't really care.
> > - Fix homedir/tmpdir typo in chcon call
>
> > sandbox.init (maybe obsoleted?)
> > - Fix restart so it stops and starts
> > - unmount the bind mounts when stopped
> I doubt this will work. Two many locks in /tmp /home
> > - Abort with failure if any mounts fail
>
> > seunshare.c
> > - Define the mount flag MS_PRIVATE if it isn't already. The flag is only
> > defined in the latest glibc but has been in the kernel since 2005.
> > - Simplify an if-statment. Also, I'm not sure the purpose of the
> > strncmmp in that conditional, so maybe I've oversimplified.
> This is wrong. The problem comes about when you mount within the same
> directory.
>
> seunshare -t /home/dwalsh/sanbox/tmp -h /home/dwalsh/sandbox/home ...
>
> seunshare -t /tmp/sandbox/tmp -h /tmp/sandbox/home
>
> If you do not have the check one of the above will fail.
>
> In the first example if Homedir is mounted first,
> /home/dwalsh/sanbox/tmp will no longer exist when seunshare attempts to
> mount it on /tmp.
>
> Similarly, if /tmp is mounted first in the second example.
> /tmp/sandbox/home will no longer exist.
>
> You have to check to make sure one of the directories is not included in
> the other.
>
> It seems
> > like maybe an error should be thrown if tmpdir_s == pw_dir or
> > homedir_s == "/tmp", but maybe I'm missing something.
>
> See above.
>
> I was blowing up because I use
>
> ~/sandbox/tmp and ~/sandbox/home for my mountpoints.
<snip>
Below is an updated patch that makes a few changes the the latest
Sandbox Patch [1]. This requires the chcon patch [2].
Changes this patch makes:
sandbox.py
- Remove unused 'import commands'
- Uses new chcon method in libselinux [2]
- Removes the 'yum install seunshare' message
- Converts an IOError to a string for printing a warning if a file
listed in -I does not exist
sandbox.init
- Print the standard Starting/Stoping messages with the appropriate
OK/FAIL
- Abort with failure if any mounts fail
seunshare.c
- Add the MS_REC flag during mounts to perform recursive mounts
- Define the mount flags MS_PRIVATE and MS_REC if they aren't already.
The flags are only defined in the latest glibc but have been in the
kernel since 2005.
- Calls realpath(3) on tmpdir_s and homedir_s. If relative paths are
used, it wouldn't correctly detect that tmpdir is inside homedir and
change the mount order. This fixes that.
[1] http://marc.info/?l=selinux&m=127429948731841&w=2
[2] http://marc.info/?l=selinux&m=127594712200878&w=2
Signed-off-by: Chad Sellers <csellers@tresys.com>
2010-06-10 20:37:59 +00:00
|
|
|
if (mount(dst, dst, NULL, MS_PRIVATE | MS_REC, NULL) < 0) {
|
2010-06-10 20:35:55 +00:00
|
|
|
fprintf(stderr, _("Failed to make %s private: %s\n"), dst, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Author: Steve Lawrence
Email: slawrence@tresys.com
Subject: Updated sandbox patch.
Date: Mon, 07 Jun 2010 17:53:41 -0400
On Thu, 2010-05-27 at 08:57 -0400, Daniel J Walsh wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 05/26/2010 04:06 PM, Steve Lawrence wrote:
> > On Wed, 2010-05-19 at 15:59 -0400, Daniel J Walsh wrote:
> > Fixed patch that handles Spaces in homedir.
>
> > The following patch makes a few updates the the sandbox patch, though I
> > have a question:
>
> > Is the sandbox.init script needed anymore? It looks like seunshare was
> > changed to now bind mount and make private the necessary directories.
> > The only thing that seems missing is making root rshared. Also, if the
> > init script is obsolete, do the mounts also need the MS_REC flag for
> > recursive bind/private like they are mounted in the init script? e.g.
>
> The init script is needed for the xguest package/more specifically
> pam_namespace, but also needed for
> mount --make-rshared /
>
> Whether the init script belongs in policycoreutils is questionable though.
>
>
> > mount(dst, dst, NULL, (MS_BIND | MS_REC), NULL)
> > mount(dst, dst, NULL, (MS_PRIVATE | MS_REC), NULL)
>
> We probably should add these. Although it is not likely.
>
> > Changes the following patch makes:
>
> > sandbox.py
> > - Removes unused 'import commands'
> > - Fixes the chcon function, and replaces the deprecated os.path.walk
> > with os.walk. I think this way is a bit easier to read too.
>
> I think chcon should be added to libselinux python bindings and then
> leave the recursive flag. (restorecon is currently in python bindings._
>
> > - Removes the 'yum install seunshare' message. This tool is not specific
> > to RPM based distros.
>
> People are using seunshare without X now that I have added the -M flag.
> So I will move it from the -gui package to the base package with
> sandbox and then this should not be necessary.
> > - Remove try/except around -I include to be consistent with the -i
> > option. If we can't include a file, then this should bail, no matter
> > if it's being included via -i or -I.
>
> Ok, I was thinking you could list a whole bunch of files in the -I case
> and if one does not exist, allow it to continue. But I don't really care.
> > - Fix homedir/tmpdir typo in chcon call
>
> > sandbox.init (maybe obsoleted?)
> > - Fix restart so it stops and starts
> > - unmount the bind mounts when stopped
> I doubt this will work. Two many locks in /tmp /home
> > - Abort with failure if any mounts fail
>
> > seunshare.c
> > - Define the mount flag MS_PRIVATE if it isn't already. The flag is only
> > defined in the latest glibc but has been in the kernel since 2005.
> > - Simplify an if-statment. Also, I'm not sure the purpose of the
> > strncmmp in that conditional, so maybe I've oversimplified.
> This is wrong. The problem comes about when you mount within the same
> directory.
>
> seunshare -t /home/dwalsh/sanbox/tmp -h /home/dwalsh/sandbox/home ...
>
> seunshare -t /tmp/sandbox/tmp -h /tmp/sandbox/home
>
> If you do not have the check one of the above will fail.
>
> In the first example if Homedir is mounted first,
> /home/dwalsh/sanbox/tmp will no longer exist when seunshare attempts to
> mount it on /tmp.
>
> Similarly, if /tmp is mounted first in the second example.
> /tmp/sandbox/home will no longer exist.
>
> You have to check to make sure one of the directories is not included in
> the other.
>
> It seems
> > like maybe an error should be thrown if tmpdir_s == pw_dir or
> > homedir_s == "/tmp", but maybe I'm missing something.
>
> See above.
>
> I was blowing up because I use
>
> ~/sandbox/tmp and ~/sandbox/home for my mountpoints.
<snip>
Below is an updated patch that makes a few changes the the latest
Sandbox Patch [1]. This requires the chcon patch [2].
Changes this patch makes:
sandbox.py
- Remove unused 'import commands'
- Uses new chcon method in libselinux [2]
- Removes the 'yum install seunshare' message
- Converts an IOError to a string for printing a warning if a file
listed in -I does not exist
sandbox.init
- Print the standard Starting/Stoping messages with the appropriate
OK/FAIL
- Abort with failure if any mounts fail
seunshare.c
- Add the MS_REC flag during mounts to perform recursive mounts
- Define the mount flags MS_PRIVATE and MS_REC if they aren't already.
The flags are only defined in the latest glibc but have been in the
kernel since 2005.
- Calls realpath(3) on tmpdir_s and homedir_s. If relative paths are
used, it wouldn't correctly detect that tmpdir is inside homedir and
change the mount order. This fixes that.
[1] http://marc.info/?l=selinux&m=127429948731841&w=2
[2] http://marc.info/?l=selinux&m=127594712200878&w=2
Signed-off-by: Chad Sellers <csellers@tresys.com>
2010-06-10 20:37:59 +00:00
|
|
|
if (mount(src, dst, NULL, MS_BIND | MS_REC, NULL) < 0) {
|
2010-06-10 20:35:55 +00:00
|
|
|
fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verify_mount(dst, pwd) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-08-03 19:09:22 +00:00
|
|
|
/**
|
|
|
|
* Error logging used by cgroups code.
|
|
|
|
*/
|
|
|
|
static int sandbox_error(const char *string)
|
|
|
|
{
|
|
|
|
fprintf(stderr, string);
|
|
|
|
syslog(LOG_AUTHPRIV | LOG_ALERT, string);
|
|
|
|
exit(-1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Regular expression match.
|
|
|
|
*/
|
|
|
|
static int match(const char *string, char *pattern)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
regex_t re;
|
|
|
|
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
status = regexec(&re, string, (size_t)0, NULL, 0);
|
|
|
|
regfree(&re);
|
|
|
|
if (status != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Apply cgroups settings from the /etc/sysconfig/sandbox config file.
|
|
|
|
*/
|
|
|
|
static int setup_cgroups()
|
|
|
|
{
|
|
|
|
char *cpus = NULL; /* which CPUs to use */
|
|
|
|
char *cgroupname = NULL;/* name for the cgroup */
|
|
|
|
char *mem = NULL; /* string for memory amount to pass to cgroup */
|
|
|
|
int64_t memusage = 0; /* amount of memory to use max (percent) */
|
|
|
|
int cpupercentage = 0; /* what percentage of cpu to allow usage */
|
|
|
|
FILE* fp;
|
|
|
|
char buf[BUF_SIZE];
|
|
|
|
char *tok = NULL;
|
|
|
|
int rc = -1;
|
|
|
|
char *str = NULL;
|
|
|
|
const char* fname = "/etc/sysconfig/sandbox";
|
|
|
|
|
|
|
|
if ((fp = fopen(fname, "rt")) == NULL) {
|
|
|
|
fprintf(stderr, "Error opening sandbox config file.");
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
while(fgets(buf, BUF_SIZE, fp) != NULL) {
|
|
|
|
/* Skip comments */
|
|
|
|
if (buf[0] == '#') continue;
|
|
|
|
|
|
|
|
/* Copy the string, ignoring whitespace */
|
|
|
|
int len = strlen(buf);
|
|
|
|
free(str);
|
|
|
|
str = malloc((len + 1) * sizeof(char));
|
|
|
|
if (!str)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
int ind = 0;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
char cur = buf[i];
|
|
|
|
if (cur != ' ' && cur != '\t') {
|
|
|
|
str[ind] = cur;
|
|
|
|
ind++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
str[ind] = '\0';
|
|
|
|
|
|
|
|
tok = strtok(str, "=\n");
|
|
|
|
if (tok != NULL) {
|
|
|
|
if (!strcmp(tok, "CPUAFFINITY")) {
|
|
|
|
tok = strtok(NULL, "=\n");
|
|
|
|
cpus = strdup(tok);
|
|
|
|
if (!strcmp(cpus, "ALL")) {
|
|
|
|
free(cpus);
|
|
|
|
cpus = NULL;
|
|
|
|
}
|
|
|
|
} else if (!strcmp(tok, "MEMUSAGE")) {
|
|
|
|
tok = strtok(NULL, "=\n");
|
|
|
|
if (match(tok, "^[0-9]+[kKmMgG%]")) {
|
|
|
|
char *ind = strchr(tok, '%');
|
|
|
|
if (ind != NULL) {
|
|
|
|
*ind = '\0';;
|
|
|
|
memusage = atoi(tok);
|
|
|
|
} else {
|
|
|
|
mem = strdup(tok);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Error parsing config file.");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (!strcmp(tok, "CPUUSAGE")) {
|
|
|
|
tok = strtok(NULL, "=\n");
|
|
|
|
if (match(tok, "^[0-9]+\%")) {
|
|
|
|
char* ind = strchr(tok, '%');
|
|
|
|
*ind = '\0';
|
|
|
|
cpupercentage = atoi(tok);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Error parsing config file.");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
} else if (!strcmp(tok, "NAME")) {
|
|
|
|
tok = strtok(NULL, "=\n");
|
|
|
|
cgroupname = strdup(tok);
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if (mem == NULL) {
|
|
|
|
long phypz = sysconf(_SC_PHYS_PAGES);
|
|
|
|
long psize = sysconf(_SC_PAGE_SIZE);
|
|
|
|
memusage = phypz * psize * (float) memusage / 100.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cgroup_init();
|
|
|
|
|
|
|
|
int64_t current_runtime = 0;
|
|
|
|
int64_t current_period = 0 ;
|
|
|
|
int64_t current_mem = 0;
|
|
|
|
char *curr_cpu_path = NULL;
|
|
|
|
char *curr_mem_path = NULL;
|
|
|
|
int ret = cgroup_get_current_controller_path(getpid(), "cpu", &curr_cpu_path);
|
|
|
|
if (ret) {
|
|
|
|
sandbox_error("Error while trying to get current controller path.\n");
|
|
|
|
} else {
|
|
|
|
struct cgroup *curr = cgroup_new_cgroup(curr_cpu_path);
|
|
|
|
cgroup_get_cgroup(curr);
|
|
|
|
cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_runtime_us", ¤t_runtime);
|
|
|
|
cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_period_us", ¤t_period);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = cgroup_get_current_controller_path(getpid(), "memory", &curr_mem_path);
|
|
|
|
if (ret) {
|
|
|
|
sandbox_error("Error while trying to get current controller path.\n");
|
|
|
|
} else {
|
|
|
|
struct cgroup *curr = cgroup_new_cgroup(curr_mem_path);
|
|
|
|
cgroup_get_cgroup(curr);
|
|
|
|
cgroup_get_value_int64(cgroup_get_controller(curr, "memory"), "memory.limit_in_bytes", ¤t_mem);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (((float) cpupercentage) / 100.0> (float)current_runtime / (float) current_period) {
|
|
|
|
sandbox_error("CPU usage restricted!\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mem == NULL) {
|
|
|
|
if (memusage > current_mem) {
|
|
|
|
sandbox_error("Attempting to use more memory than allowed!");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
long nprocs = sysconf(_SC_NPROCESSORS_ONLN);
|
|
|
|
|
|
|
|
struct sched_param sp;
|
|
|
|
sp.sched_priority = sched_get_priority_min(SCHED_FIFO);
|
|
|
|
sched_setscheduler(getpid(), SCHED_FIFO, &sp);
|
|
|
|
struct cgroup *sandbox_group = cgroup_new_cgroup(cgroupname);
|
|
|
|
cgroup_add_controller(sandbox_group, "memory");
|
|
|
|
cgroup_add_controller(sandbox_group, "cpu");
|
|
|
|
|
|
|
|
if (mem == NULL) {
|
|
|
|
if (memusage > 0) {
|
|
|
|
cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", memusage);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cgroup_set_value_string(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", mem);
|
|
|
|
}
|
|
|
|
if (cpupercentage > 0) {
|
|
|
|
cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_runtime_us",
|
|
|
|
(float) cpupercentage / 100.0 * 60000);
|
|
|
|
cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_period_us",60000 * nprocs);
|
|
|
|
}
|
|
|
|
if (cpus != NULL) {
|
|
|
|
cgroup_set_value_string(cgroup_get_controller(sandbox_group, "cpu"), "cgroup.procs",cpus);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t allocated_mem;
|
|
|
|
if (cgroup_get_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", &allocated_mem) > current_mem) {
|
|
|
|
sandbox_error("Attempting to use more memory than allowed!\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = cgroup_create_cgroup(sandbox_group, 1);
|
|
|
|
if (rc != 0) {
|
|
|
|
sandbox_error("Failed to create group. Ensure that cgconfig service is running. \n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
cgroup_attach_task(sandbox_group);
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
err:
|
|
|
|
fclose(fp);
|
|
|
|
free(str);
|
|
|
|
free(mem);
|
|
|
|
free(cgroupname);
|
|
|
|
free(cpus);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-06-10 20:35:55 +00:00
|
|
|
int main(int argc, char **argv) {
|
|
|
|
int rc;
|
|
|
|
int status = -1;
|
|
|
|
|
2011-08-15 20:00:04 +00:00
|
|
|
security_context_t scontext = NULL;
|
2010-06-10 20:35:55 +00:00
|
|
|
|
|
|
|
int flag_index; /* flag index in argv[] */
|
|
|
|
int clflag; /* holds codes for command line flags */
|
|
|
|
char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */
|
|
|
|
char *homedir_s = NULL; /* homedir spec'd by user in argv[] */
|
2011-08-03 19:09:22 +00:00
|
|
|
int usecgroups = 0;
|
2010-06-10 20:35:55 +00:00
|
|
|
|
|
|
|
const struct option long_options[] = {
|
|
|
|
{"homedir", 1, 0, 'h'},
|
|
|
|
{"tmpdir", 1, 0, 't'},
|
|
|
|
{"verbose", 1, 0, 'v'},
|
2011-08-03 19:09:22 +00:00
|
|
|
{"cgroups", 1, 0, 'c'},
|
2011-08-15 20:00:04 +00:00
|
|
|
{"context", 1, 0, 'Z'},
|
2011-06-13 17:24:38 +00:00
|
|
|
{"capabilities", 1, 0, 'C'},
|
2010-06-10 20:35:55 +00:00
|
|
|
{NULL, 0, 0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
uid_t uid = getuid();
|
2011-07-26 14:42:26 +00:00
|
|
|
/*
|
2010-06-10 20:35:55 +00:00
|
|
|
if (!uid) {
|
|
|
|
fprintf(stderr, _("Must not be root"));
|
|
|
|
return -1;
|
|
|
|
}
|
2011-07-26 14:42:26 +00:00
|
|
|
*/
|
2010-06-10 20:35:55 +00:00
|
|
|
|
|
|
|
struct passwd *pwd=getpwuid(uid);
|
|
|
|
if (!pwd) {
|
|
|
|
perror(_("getpwduid failed"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verify_shell(pwd->pw_shell) < 0) {
|
|
|
|
fprintf(stderr, _("Error! Shell is not valid.\n"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
2011-06-13 17:24:38 +00:00
|
|
|
clflag = getopt_long(argc, argv, "Ccvh:t:Z:", long_options, NULL);
|
2010-06-10 20:35:55 +00:00
|
|
|
if (clflag == -1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch (clflag) {
|
|
|
|
case 't':
|
Author: Steve Lawrence
Email: slawrence@tresys.com
Subject: Updated sandbox patch.
Date: Mon, 07 Jun 2010 17:53:41 -0400
On Thu, 2010-05-27 at 08:57 -0400, Daniel J Walsh wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 05/26/2010 04:06 PM, Steve Lawrence wrote:
> > On Wed, 2010-05-19 at 15:59 -0400, Daniel J Walsh wrote:
> > Fixed patch that handles Spaces in homedir.
>
> > The following patch makes a few updates the the sandbox patch, though I
> > have a question:
>
> > Is the sandbox.init script needed anymore? It looks like seunshare was
> > changed to now bind mount and make private the necessary directories.
> > The only thing that seems missing is making root rshared. Also, if the
> > init script is obsolete, do the mounts also need the MS_REC flag for
> > recursive bind/private like they are mounted in the init script? e.g.
>
> The init script is needed for the xguest package/more specifically
> pam_namespace, but also needed for
> mount --make-rshared /
>
> Whether the init script belongs in policycoreutils is questionable though.
>
>
> > mount(dst, dst, NULL, (MS_BIND | MS_REC), NULL)
> > mount(dst, dst, NULL, (MS_PRIVATE | MS_REC), NULL)
>
> We probably should add these. Although it is not likely.
>
> > Changes the following patch makes:
>
> > sandbox.py
> > - Removes unused 'import commands'
> > - Fixes the chcon function, and replaces the deprecated os.path.walk
> > with os.walk. I think this way is a bit easier to read too.
>
> I think chcon should be added to libselinux python bindings and then
> leave the recursive flag. (restorecon is currently in python bindings._
>
> > - Removes the 'yum install seunshare' message. This tool is not specific
> > to RPM based distros.
>
> People are using seunshare without X now that I have added the -M flag.
> So I will move it from the -gui package to the base package with
> sandbox and then this should not be necessary.
> > - Remove try/except around -I include to be consistent with the -i
> > option. If we can't include a file, then this should bail, no matter
> > if it's being included via -i or -I.
>
> Ok, I was thinking you could list a whole bunch of files in the -I case
> and if one does not exist, allow it to continue. But I don't really care.
> > - Fix homedir/tmpdir typo in chcon call
>
> > sandbox.init (maybe obsoleted?)
> > - Fix restart so it stops and starts
> > - unmount the bind mounts when stopped
> I doubt this will work. Two many locks in /tmp /home
> > - Abort with failure if any mounts fail
>
> > seunshare.c
> > - Define the mount flag MS_PRIVATE if it isn't already. The flag is only
> > defined in the latest glibc but has been in the kernel since 2005.
> > - Simplify an if-statment. Also, I'm not sure the purpose of the
> > strncmmp in that conditional, so maybe I've oversimplified.
> This is wrong. The problem comes about when you mount within the same
> directory.
>
> seunshare -t /home/dwalsh/sanbox/tmp -h /home/dwalsh/sandbox/home ...
>
> seunshare -t /tmp/sandbox/tmp -h /tmp/sandbox/home
>
> If you do not have the check one of the above will fail.
>
> In the first example if Homedir is mounted first,
> /home/dwalsh/sanbox/tmp will no longer exist when seunshare attempts to
> mount it on /tmp.
>
> Similarly, if /tmp is mounted first in the second example.
> /tmp/sandbox/home will no longer exist.
>
> You have to check to make sure one of the directories is not included in
> the other.
>
> It seems
> > like maybe an error should be thrown if tmpdir_s == pw_dir or
> > homedir_s == "/tmp", but maybe I'm missing something.
>
> See above.
>
> I was blowing up because I use
>
> ~/sandbox/tmp and ~/sandbox/home for my mountpoints.
<snip>
Below is an updated patch that makes a few changes the the latest
Sandbox Patch [1]. This requires the chcon patch [2].
Changes this patch makes:
sandbox.py
- Remove unused 'import commands'
- Uses new chcon method in libselinux [2]
- Removes the 'yum install seunshare' message
- Converts an IOError to a string for printing a warning if a file
listed in -I does not exist
sandbox.init
- Print the standard Starting/Stoping messages with the appropriate
OK/FAIL
- Abort with failure if any mounts fail
seunshare.c
- Add the MS_REC flag during mounts to perform recursive mounts
- Define the mount flags MS_PRIVATE and MS_REC if they aren't already.
The flags are only defined in the latest glibc but have been in the
kernel since 2005.
- Calls realpath(3) on tmpdir_s and homedir_s. If relative paths are
used, it wouldn't correctly detect that tmpdir is inside homedir and
change the mount order. This fixes that.
[1] http://marc.info/?l=selinux&m=127429948731841&w=2
[2] http://marc.info/?l=selinux&m=127594712200878&w=2
Signed-off-by: Chad Sellers <csellers@tresys.com>
2010-06-10 20:37:59 +00:00
|
|
|
if (!(tmpdir_s = realpath(optarg, NULL))) {
|
|
|
|
fprintf(stderr, _("Invalid mount point %s: %s\n"), optarg, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
2010-06-10 20:35:55 +00:00
|
|
|
if (verify_mount(tmpdir_s, pwd) < 0) return -1;
|
|
|
|
break;
|
|
|
|
case 'h':
|
Author: Steve Lawrence
Email: slawrence@tresys.com
Subject: Updated sandbox patch.
Date: Mon, 07 Jun 2010 17:53:41 -0400
On Thu, 2010-05-27 at 08:57 -0400, Daniel J Walsh wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 05/26/2010 04:06 PM, Steve Lawrence wrote:
> > On Wed, 2010-05-19 at 15:59 -0400, Daniel J Walsh wrote:
> > Fixed patch that handles Spaces in homedir.
>
> > The following patch makes a few updates the the sandbox patch, though I
> > have a question:
>
> > Is the sandbox.init script needed anymore? It looks like seunshare was
> > changed to now bind mount and make private the necessary directories.
> > The only thing that seems missing is making root rshared. Also, if the
> > init script is obsolete, do the mounts also need the MS_REC flag for
> > recursive bind/private like they are mounted in the init script? e.g.
>
> The init script is needed for the xguest package/more specifically
> pam_namespace, but also needed for
> mount --make-rshared /
>
> Whether the init script belongs in policycoreutils is questionable though.
>
>
> > mount(dst, dst, NULL, (MS_BIND | MS_REC), NULL)
> > mount(dst, dst, NULL, (MS_PRIVATE | MS_REC), NULL)
>
> We probably should add these. Although it is not likely.
>
> > Changes the following patch makes:
>
> > sandbox.py
> > - Removes unused 'import commands'
> > - Fixes the chcon function, and replaces the deprecated os.path.walk
> > with os.walk. I think this way is a bit easier to read too.
>
> I think chcon should be added to libselinux python bindings and then
> leave the recursive flag. (restorecon is currently in python bindings._
>
> > - Removes the 'yum install seunshare' message. This tool is not specific
> > to RPM based distros.
>
> People are using seunshare without X now that I have added the -M flag.
> So I will move it from the -gui package to the base package with
> sandbox and then this should not be necessary.
> > - Remove try/except around -I include to be consistent with the -i
> > option. If we can't include a file, then this should bail, no matter
> > if it's being included via -i or -I.
>
> Ok, I was thinking you could list a whole bunch of files in the -I case
> and if one does not exist, allow it to continue. But I don't really care.
> > - Fix homedir/tmpdir typo in chcon call
>
> > sandbox.init (maybe obsoleted?)
> > - Fix restart so it stops and starts
> > - unmount the bind mounts when stopped
> I doubt this will work. Two many locks in /tmp /home
> > - Abort with failure if any mounts fail
>
> > seunshare.c
> > - Define the mount flag MS_PRIVATE if it isn't already. The flag is only
> > defined in the latest glibc but has been in the kernel since 2005.
> > - Simplify an if-statment. Also, I'm not sure the purpose of the
> > strncmmp in that conditional, so maybe I've oversimplified.
> This is wrong. The problem comes about when you mount within the same
> directory.
>
> seunshare -t /home/dwalsh/sanbox/tmp -h /home/dwalsh/sandbox/home ...
>
> seunshare -t /tmp/sandbox/tmp -h /tmp/sandbox/home
>
> If you do not have the check one of the above will fail.
>
> In the first example if Homedir is mounted first,
> /home/dwalsh/sanbox/tmp will no longer exist when seunshare attempts to
> mount it on /tmp.
>
> Similarly, if /tmp is mounted first in the second example.
> /tmp/sandbox/home will no longer exist.
>
> You have to check to make sure one of the directories is not included in
> the other.
>
> It seems
> > like maybe an error should be thrown if tmpdir_s == pw_dir or
> > homedir_s == "/tmp", but maybe I'm missing something.
>
> See above.
>
> I was blowing up because I use
>
> ~/sandbox/tmp and ~/sandbox/home for my mountpoints.
<snip>
Below is an updated patch that makes a few changes the the latest
Sandbox Patch [1]. This requires the chcon patch [2].
Changes this patch makes:
sandbox.py
- Remove unused 'import commands'
- Uses new chcon method in libselinux [2]
- Removes the 'yum install seunshare' message
- Converts an IOError to a string for printing a warning if a file
listed in -I does not exist
sandbox.init
- Print the standard Starting/Stoping messages with the appropriate
OK/FAIL
- Abort with failure if any mounts fail
seunshare.c
- Add the MS_REC flag during mounts to perform recursive mounts
- Define the mount flags MS_PRIVATE and MS_REC if they aren't already.
The flags are only defined in the latest glibc but have been in the
kernel since 2005.
- Calls realpath(3) on tmpdir_s and homedir_s. If relative paths are
used, it wouldn't correctly detect that tmpdir is inside homedir and
change the mount order. This fixes that.
[1] http://marc.info/?l=selinux&m=127429948731841&w=2
[2] http://marc.info/?l=selinux&m=127594712200878&w=2
Signed-off-by: Chad Sellers <csellers@tresys.com>
2010-06-10 20:37:59 +00:00
|
|
|
if (!(homedir_s = realpath(optarg, NULL))) {
|
|
|
|
fprintf(stderr, _("Invalid mount point %s: %s\n"), optarg, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
2010-06-10 20:35:55 +00:00
|
|
|
if (verify_mount(homedir_s, pwd) < 0) return -1;
|
|
|
|
if (verify_mount(pwd->pw_dir, pwd) < 0) return -1;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
verbose = 1;
|
|
|
|
break;
|
2011-08-03 19:09:22 +00:00
|
|
|
case 'c':
|
|
|
|
usecgroups = 1;
|
|
|
|
break;
|
2011-06-13 17:24:38 +00:00
|
|
|
case 'C':
|
|
|
|
cap_set = CAPNG_SELECT_CAPS;
|
|
|
|
break;
|
2011-08-15 20:00:04 +00:00
|
|
|
case 'Z':
|
|
|
|
scontext = strdup(optarg);
|
|
|
|
break;
|
2010-06-10 20:35:55 +00:00
|
|
|
default:
|
|
|
|
fprintf(stderr, "%s\n", USAGE_STRING);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! homedir_s && ! tmpdir_s) {
|
|
|
|
fprintf(stderr, _("Error: tmpdir and/or homedir required \n"),
|
|
|
|
"%s\n", USAGE_STRING);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-08-15 20:00:04 +00:00
|
|
|
if (argc - optind < 1) {
|
|
|
|
fprintf(stderr, _("Error: executable required \n %s \n"), USAGE_STRING);
|
2010-06-10 20:35:55 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (set_signal_handles())
|
|
|
|
return -1;
|
|
|
|
|
2011-08-03 19:09:22 +00:00
|
|
|
if (usecgroups && setup_cgroups() < 0)
|
|
|
|
return -1;
|
|
|
|
|
2010-06-10 20:35:55 +00:00
|
|
|
if (unshare(CLONE_NEWNS) < 0) {
|
|
|
|
perror(_("Failed to unshare"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (homedir_s && tmpdir_s && (strncmp(pwd->pw_dir, tmpdir_s, strlen(pwd->pw_dir)) == 0)) {
|
|
|
|
if (seunshare_mount(tmpdir_s, "/tmp", pwd) < 0)
|
|
|
|
return -1;
|
|
|
|
if (seunshare_mount(homedir_s, pwd->pw_dir, pwd) < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (homedir_s && seunshare_mount(homedir_s, pwd->pw_dir, pwd) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (tmpdir_s && seunshare_mount(tmpdir_s, "/tmp", pwd) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-08-05 17:33:35 +00:00
|
|
|
if (drop_privs(uid))
|
2010-06-10 20:35:55 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
int child = fork();
|
|
|
|
if (child == -1) {
|
|
|
|
perror(_("Unable to fork"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!child) {
|
|
|
|
char *display=NULL;
|
|
|
|
/* Construct a new environment */
|
|
|
|
char *d = getenv("DISPLAY");
|
|
|
|
if (d) {
|
|
|
|
display = strdup(d);
|
|
|
|
if (!display) {
|
|
|
|
perror(_("Out of memory"));
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rc = clearenv())) {
|
|
|
|
perror(_("Unable to clear environment"));
|
|
|
|
free(display);
|
|
|
|
exit(-1);
|
|
|
|
}
|
2011-08-15 20:00:04 +00:00
|
|
|
|
|
|
|
if (scontext) {
|
|
|
|
if (setexeccon(scontext)) {
|
|
|
|
fprintf(stderr, _("Could not set exec context to %s.\n"),
|
|
|
|
scontext);
|
|
|
|
free(display);
|
|
|
|
exit(-1);
|
|
|
|
}
|
2010-06-10 20:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (display)
|
|
|
|
rc |= setenv("DISPLAY", display, 1);
|
|
|
|
rc |= setenv("HOME", pwd->pw_dir, 1);
|
|
|
|
rc |= setenv("SHELL", pwd->pw_shell, 1);
|
|
|
|
rc |= setenv("USER", pwd->pw_name, 1);
|
|
|
|
rc |= setenv("LOGNAME", pwd->pw_name, 1);
|
|
|
|
rc |= setenv("PATH", DEFAULT_PATH, 1);
|
|
|
|
|
|
|
|
if (chdir(pwd->pw_dir)) {
|
|
|
|
perror(_("Failed to change dir to homedir"));
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
setsid();
|
|
|
|
execv(argv[optind], argv + optind);
|
|
|
|
free(display);
|
|
|
|
perror("execv");
|
|
|
|
exit(-1);
|
|
|
|
} else {
|
|
|
|
waitpid(child, &status, 0);
|
|
|
|
}
|
|
|
|
|
Author: Steve Lawrence
Email: slawrence@tresys.com
Subject: Updated sandbox patch.
Date: Mon, 07 Jun 2010 17:53:41 -0400
On Thu, 2010-05-27 at 08:57 -0400, Daniel J Walsh wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 05/26/2010 04:06 PM, Steve Lawrence wrote:
> > On Wed, 2010-05-19 at 15:59 -0400, Daniel J Walsh wrote:
> > Fixed patch that handles Spaces in homedir.
>
> > The following patch makes a few updates the the sandbox patch, though I
> > have a question:
>
> > Is the sandbox.init script needed anymore? It looks like seunshare was
> > changed to now bind mount and make private the necessary directories.
> > The only thing that seems missing is making root rshared. Also, if the
> > init script is obsolete, do the mounts also need the MS_REC flag for
> > recursive bind/private like they are mounted in the init script? e.g.
>
> The init script is needed for the xguest package/more specifically
> pam_namespace, but also needed for
> mount --make-rshared /
>
> Whether the init script belongs in policycoreutils is questionable though.
>
>
> > mount(dst, dst, NULL, (MS_BIND | MS_REC), NULL)
> > mount(dst, dst, NULL, (MS_PRIVATE | MS_REC), NULL)
>
> We probably should add these. Although it is not likely.
>
> > Changes the following patch makes:
>
> > sandbox.py
> > - Removes unused 'import commands'
> > - Fixes the chcon function, and replaces the deprecated os.path.walk
> > with os.walk. I think this way is a bit easier to read too.
>
> I think chcon should be added to libselinux python bindings and then
> leave the recursive flag. (restorecon is currently in python bindings._
>
> > - Removes the 'yum install seunshare' message. This tool is not specific
> > to RPM based distros.
>
> People are using seunshare without X now that I have added the -M flag.
> So I will move it from the -gui package to the base package with
> sandbox and then this should not be necessary.
> > - Remove try/except around -I include to be consistent with the -i
> > option. If we can't include a file, then this should bail, no matter
> > if it's being included via -i or -I.
>
> Ok, I was thinking you could list a whole bunch of files in the -I case
> and if one does not exist, allow it to continue. But I don't really care.
> > - Fix homedir/tmpdir typo in chcon call
>
> > sandbox.init (maybe obsoleted?)
> > - Fix restart so it stops and starts
> > - unmount the bind mounts when stopped
> I doubt this will work. Two many locks in /tmp /home
> > - Abort with failure if any mounts fail
>
> > seunshare.c
> > - Define the mount flag MS_PRIVATE if it isn't already. The flag is only
> > defined in the latest glibc but has been in the kernel since 2005.
> > - Simplify an if-statment. Also, I'm not sure the purpose of the
> > strncmmp in that conditional, so maybe I've oversimplified.
> This is wrong. The problem comes about when you mount within the same
> directory.
>
> seunshare -t /home/dwalsh/sanbox/tmp -h /home/dwalsh/sandbox/home ...
>
> seunshare -t /tmp/sandbox/tmp -h /tmp/sandbox/home
>
> If you do not have the check one of the above will fail.
>
> In the first example if Homedir is mounted first,
> /home/dwalsh/sanbox/tmp will no longer exist when seunshare attempts to
> mount it on /tmp.
>
> Similarly, if /tmp is mounted first in the second example.
> /tmp/sandbox/home will no longer exist.
>
> You have to check to make sure one of the directories is not included in
> the other.
>
> It seems
> > like maybe an error should be thrown if tmpdir_s == pw_dir or
> > homedir_s == "/tmp", but maybe I'm missing something.
>
> See above.
>
> I was blowing up because I use
>
> ~/sandbox/tmp and ~/sandbox/home for my mountpoints.
<snip>
Below is an updated patch that makes a few changes the the latest
Sandbox Patch [1]. This requires the chcon patch [2].
Changes this patch makes:
sandbox.py
- Remove unused 'import commands'
- Uses new chcon method in libselinux [2]
- Removes the 'yum install seunshare' message
- Converts an IOError to a string for printing a warning if a file
listed in -I does not exist
sandbox.init
- Print the standard Starting/Stoping messages with the appropriate
OK/FAIL
- Abort with failure if any mounts fail
seunshare.c
- Add the MS_REC flag during mounts to perform recursive mounts
- Define the mount flags MS_PRIVATE and MS_REC if they aren't already.
The flags are only defined in the latest glibc but have been in the
kernel since 2005.
- Calls realpath(3) on tmpdir_s and homedir_s. If relative paths are
used, it wouldn't correctly detect that tmpdir is inside homedir and
change the mount order. This fixes that.
[1] http://marc.info/?l=selinux&m=127429948731841&w=2
[2] http://marc.info/?l=selinux&m=127594712200878&w=2
Signed-off-by: Chad Sellers <csellers@tresys.com>
2010-06-10 20:37:59 +00:00
|
|
|
free(tmpdir_s);
|
|
|
|
free(homedir_s);
|
2011-08-15 20:00:04 +00:00
|
|
|
free(scontext);
|
Author: Steve Lawrence
Email: slawrence@tresys.com
Subject: Updated sandbox patch.
Date: Mon, 07 Jun 2010 17:53:41 -0400
On Thu, 2010-05-27 at 08:57 -0400, Daniel J Walsh wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 05/26/2010 04:06 PM, Steve Lawrence wrote:
> > On Wed, 2010-05-19 at 15:59 -0400, Daniel J Walsh wrote:
> > Fixed patch that handles Spaces in homedir.
>
> > The following patch makes a few updates the the sandbox patch, though I
> > have a question:
>
> > Is the sandbox.init script needed anymore? It looks like seunshare was
> > changed to now bind mount and make private the necessary directories.
> > The only thing that seems missing is making root rshared. Also, if the
> > init script is obsolete, do the mounts also need the MS_REC flag for
> > recursive bind/private like they are mounted in the init script? e.g.
>
> The init script is needed for the xguest package/more specifically
> pam_namespace, but also needed for
> mount --make-rshared /
>
> Whether the init script belongs in policycoreutils is questionable though.
>
>
> > mount(dst, dst, NULL, (MS_BIND | MS_REC), NULL)
> > mount(dst, dst, NULL, (MS_PRIVATE | MS_REC), NULL)
>
> We probably should add these. Although it is not likely.
>
> > Changes the following patch makes:
>
> > sandbox.py
> > - Removes unused 'import commands'
> > - Fixes the chcon function, and replaces the deprecated os.path.walk
> > with os.walk. I think this way is a bit easier to read too.
>
> I think chcon should be added to libselinux python bindings and then
> leave the recursive flag. (restorecon is currently in python bindings._
>
> > - Removes the 'yum install seunshare' message. This tool is not specific
> > to RPM based distros.
>
> People are using seunshare without X now that I have added the -M flag.
> So I will move it from the -gui package to the base package with
> sandbox and then this should not be necessary.
> > - Remove try/except around -I include to be consistent with the -i
> > option. If we can't include a file, then this should bail, no matter
> > if it's being included via -i or -I.
>
> Ok, I was thinking you could list a whole bunch of files in the -I case
> and if one does not exist, allow it to continue. But I don't really care.
> > - Fix homedir/tmpdir typo in chcon call
>
> > sandbox.init (maybe obsoleted?)
> > - Fix restart so it stops and starts
> > - unmount the bind mounts when stopped
> I doubt this will work. Two many locks in /tmp /home
> > - Abort with failure if any mounts fail
>
> > seunshare.c
> > - Define the mount flag MS_PRIVATE if it isn't already. The flag is only
> > defined in the latest glibc but has been in the kernel since 2005.
> > - Simplify an if-statment. Also, I'm not sure the purpose of the
> > strncmmp in that conditional, so maybe I've oversimplified.
> This is wrong. The problem comes about when you mount within the same
> directory.
>
> seunshare -t /home/dwalsh/sanbox/tmp -h /home/dwalsh/sandbox/home ...
>
> seunshare -t /tmp/sandbox/tmp -h /tmp/sandbox/home
>
> If you do not have the check one of the above will fail.
>
> In the first example if Homedir is mounted first,
> /home/dwalsh/sanbox/tmp will no longer exist when seunshare attempts to
> mount it on /tmp.
>
> Similarly, if /tmp is mounted first in the second example.
> /tmp/sandbox/home will no longer exist.
>
> You have to check to make sure one of the directories is not included in
> the other.
>
> It seems
> > like maybe an error should be thrown if tmpdir_s == pw_dir or
> > homedir_s == "/tmp", but maybe I'm missing something.
>
> See above.
>
> I was blowing up because I use
>
> ~/sandbox/tmp and ~/sandbox/home for my mountpoints.
<snip>
Below is an updated patch that makes a few changes the the latest
Sandbox Patch [1]. This requires the chcon patch [2].
Changes this patch makes:
sandbox.py
- Remove unused 'import commands'
- Uses new chcon method in libselinux [2]
- Removes the 'yum install seunshare' message
- Converts an IOError to a string for printing a warning if a file
listed in -I does not exist
sandbox.init
- Print the standard Starting/Stoping messages with the appropriate
OK/FAIL
- Abort with failure if any mounts fail
seunshare.c
- Add the MS_REC flag during mounts to perform recursive mounts
- Define the mount flags MS_PRIVATE and MS_REC if they aren't already.
The flags are only defined in the latest glibc but have been in the
kernel since 2005.
- Calls realpath(3) on tmpdir_s and homedir_s. If relative paths are
used, it wouldn't correctly detect that tmpdir is inside homedir and
change the mount order. This fixes that.
[1] http://marc.info/?l=selinux&m=127429948731841&w=2
[2] http://marc.info/?l=selinux&m=127594712200878&w=2
Signed-off-by: Chad Sellers <csellers@tresys.com>
2010-06-10 20:37:59 +00:00
|
|
|
|
2010-06-10 20:35:55 +00:00
|
|
|
return status;
|
|
|
|
}
|