summaryrefslogtreecommitdiff
path: root/modules/pam_namespace
diff options
context:
space:
mode:
authorSteve Langasek <steve.langasek@ubuntu.com>2019-01-03 21:13:04 -0800
committerSteve Langasek <steve.langasek@ubuntu.com>2019-01-03 21:13:04 -0800
commitc55c14c5c6762139ec6695d84ea0e2e917da5264 (patch)
tree9e6119760c93841b2bc3e05680ac9e4e15ae9c25 /modules/pam_namespace
parentf3c0273b7bd2d7fdcac3fe3604cedd82afc57f49 (diff)
parentfc772e7236a7aea9c9c26b0be2ee6f3ed8ae444a (diff)
New upstream version 1.1.5
Diffstat (limited to 'modules/pam_namespace')
-rw-r--r--modules/pam_namespace/argv_parse.c29
-rw-r--r--modules/pam_namespace/md5.c2
-rw-r--r--modules/pam_namespace/pam_namespace.8.xml21
-rw-r--r--modules/pam_namespace/pam_namespace.c105
-rw-r--r--modules/pam_namespace/pam_namespace.h9
5 files changed, 138 insertions, 28 deletions
diff --git a/modules/pam_namespace/argv_parse.c b/modules/pam_namespace/argv_parse.c
index acc76d74..40510542 100644
--- a/modules/pam_namespace/argv_parse.c
+++ b/modules/pam_namespace/argv_parse.c
@@ -44,15 +44,15 @@ int argv_parse(const char *in_buf, int *ret_argc, char ***ret_argv)
{
int argc = 0, max_argc = 0;
char **argv, **new_argv, *buf, ch;
- const char *cp = 0;
- char *outcp = 0;
+ const char *cp = NULL;
+ char *outcp = NULL;
int state = STATE_WHITESPACE;
buf = malloc(strlen(in_buf)+1);
if (!buf)
return -1;
- max_argc = 0; argc = 0; argv = 0;
+ argv = NULL;
outcp = buf;
for (cp = in_buf; (ch = *cp); cp++) {
if (state == STATE_WHITESPACE) {
@@ -111,23 +111,30 @@ int argv_parse(const char *in_buf, int *ret_argc, char ***ret_argv)
}
if (state != STATE_WHITESPACE)
*outcp++ = '\0';
- if (argv == 0) {
- argv = malloc(sizeof(char *));
+ if (ret_argv) {
+ if (argv == NULL) {
+ free(buf);
+ if ((argv=malloc(sizeof(char *))) == NULL)
+ return -1;
+ }
+ argv[argc] = NULL;
+ *ret_argv = argv;
+ } else {
free(buf);
+ free(argv);
}
- argv[argc] = 0;
if (ret_argc)
*ret_argc = argc;
- if (ret_argv)
- *ret_argv = argv;
return 0;
}
void argv_free(char **argv)
{
- if (*argv)
- free(*argv);
- free(argv);
+ if (argv) {
+ if (*argv)
+ free(*argv);
+ free(argv);
+ }
}
#ifdef DEBUG_ARGV_PARSE
diff --git a/modules/pam_namespace/md5.c b/modules/pam_namespace/md5.c
index 9a060d27..b23d1607 100644
--- a/modules/pam_namespace/md5.c
+++ b/modules/pam_namespace/md5.c
@@ -148,7 +148,7 @@ void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx)
MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
- memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
diff --git a/modules/pam_namespace/pam_namespace.8.xml b/modules/pam_namespace/pam_namespace.8.xml
index 0433f0fd..48021c80 100644
--- a/modules/pam_namespace/pam_namespace.8.xml
+++ b/modules/pam_namespace/pam_namespace.8.xml
@@ -52,6 +52,9 @@
<arg choice="opt">
use_default_context
</arg>
+ <arg choice="opt">
+ mount_private
+ </arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -234,6 +237,24 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option>mount_private</option>
+ </term>
+ <listitem>
+ <para>
+ This option can be used on systems where the / mount point or
+ its submounts are made shared (for example with a
+ <command>mount --make-rshared /</command> command).
+ The module will make the polyinstantiated directory mount points
+ private. Normally the pam_namespace will try to detect the
+ shared / mount point and make the polyinstantiated directories
+ private automatically. This option has to be used just when
+ only a subtree is shared and / is not.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
diff --git a/modules/pam_namespace/pam_namespace.c b/modules/pam_namespace/pam_namespace.c
index a13f9599..4a99184a 100644
--- a/modules/pam_namespace/pam_namespace.c
+++ b/modules/pam_namespace/pam_namespace.c
@@ -61,9 +61,11 @@ static void add_polydir_entry(struct instance_data *idata,
static void del_polydir(struct polydir_s *poly)
{
- free(poly->uid);
- free(poly->init_script);
- free(poly);
+ if (poly) {
+ free(poly->uid);
+ free(poly->init_script);
+ free(poly);
+ }
}
/*
@@ -307,10 +309,6 @@ static int process_line(char *line, const char *home, const char *rhome,
const char *rvar_values[] = {rhome, idata->ruser};
int len;
- poly = calloc(1, sizeof(*poly));
- if (poly == NULL)
- goto erralloc;
-
/*
* skip the leading white space
*/
@@ -337,6 +335,10 @@ static int process_line(char *line, const char *home, const char *rhome,
if (line[0] == 0)
return 0;
+ poly = calloc(1, sizeof(*poly));
+ if (poly == NULL)
+ goto erralloc;
+
/*
* Initialize and scan the five strings from the line from the
* namespace configuration file.
@@ -1001,7 +1003,7 @@ static int protect_mount(int dfd, const char *path, struct instance_data *idata)
return 0;
}
-static int protect_dir(const char *path, mode_t mode, int do_mkdir,
+static int protect_dir(const char *path, mode_t mode, int do_mkdir, int always,
struct instance_data *idata)
{
char *p = strdup(path);
@@ -1080,7 +1082,7 @@ static int protect_dir(const char *path, mode_t mode, int do_mkdir,
}
}
- if (flags & O_NOFOLLOW) {
+ if ((flags & O_NOFOLLOW) || always) {
/* we are inside user-owned dir - protect */
if (protect_mount(rv, p, idata) == -1) {
save_errno = errno;
@@ -1093,7 +1095,7 @@ static int protect_dir(const char *path, mode_t mode, int do_mkdir,
error:
save_errno = errno;
free(p);
- if (dfd != AT_FDCWD)
+ if (dfd != AT_FDCWD && dfd >= 0)
close(dfd);
errno = save_errno;
@@ -1122,7 +1124,7 @@ static int check_inst_parent(char *ipath, struct instance_data *idata)
if (trailing_slash)
*trailing_slash = '\0';
- dfd = protect_dir(inst_parent, 0, 1, idata);
+ dfd = protect_dir(inst_parent, 0, 1, 0, idata);
if (dfd == -1 || fstat(dfd, &instpbuf) < 0) {
pam_syslog(idata->pamh, LOG_ERR,
@@ -1257,7 +1259,7 @@ static int create_polydir(struct polydir_s *polyptr,
}
#endif
- rc = protect_dir(dir, mode, 1, idata);
+ rc = protect_dir(dir, mode, 1, idata->flags & PAMNS_MOUNT_PRIVATE, idata);
if (rc == -1) {
pam_syslog(idata->pamh, LOG_ERR,
"Error creating directory %s: %m", dir);
@@ -1445,7 +1447,7 @@ static int ns_setup(struct polydir_s *polyptr,
pam_syslog(idata->pamh, LOG_DEBUG,
"Set namespace for directory %s", polyptr->dir);
- retval = protect_dir(polyptr->dir, 0, 0, idata);
+ retval = protect_dir(polyptr->dir, 0, 0, idata->flags & PAMNS_MOUNT_PRIVATE, idata);
if (retval < 0 && errno != ENOENT) {
pam_syslog(idata->pamh, LOG_ERR, "Polydir %s access error: %m",
@@ -1453,8 +1455,9 @@ static int ns_setup(struct polydir_s *polyptr,
return PAM_SESSION_ERR;
}
- if (retval < 0 && (polyptr->flags & POLYDIR_CREATE)) {
- if (create_polydir(polyptr, idata) != PAM_SUCCESS)
+ if (retval < 0) {
+ if ((polyptr->flags & POLYDIR_CREATE) &&
+ create_polydir(polyptr, idata) != PAM_SUCCESS)
return PAM_SESSION_ERR;
} else {
close(retval);
@@ -1531,6 +1534,22 @@ static int ns_setup(struct polydir_s *polyptr,
goto error_out;
}
+ if (idata->flags & PAMNS_MOUNT_PRIVATE) {
+ /*
+ * Make the polyinstantiated dir private mount. This depends
+ * on making the dir a mount point in the protect_dir call.
+ */
+ if (mount(polyptr->dir, polyptr->dir, NULL, MS_PRIVATE|MS_REC, NULL) < 0) {
+ pam_syslog(idata->pamh, LOG_ERR, "Error making %s a private mount, %m",
+ polyptr->dir);
+ goto error_out;
+ }
+ if (idata->flags & PAMNS_DEBUG)
+ pam_syslog(idata->pamh, LOG_DEBUG,
+ "Polyinstantiated directory %s made as private mount", polyptr->dir);
+
+ }
+
/*
* Bind mount instance directory on top of the polyinstantiated
* directory to provide an instance of polyinstantiated directory
@@ -1871,6 +1890,53 @@ static int ctxt_based_inst_needed(void)
}
#endif
+static int root_shared(void)
+{
+ FILE *f;
+ char *line = NULL;
+ size_t n = 0;
+ int rv = 0;
+
+ f = fopen("/proc/self/mountinfo", "r");
+
+ if (f == NULL)
+ return 0;
+
+ while(getline(&line, &n, f) != -1) {
+ char *l;
+ char *sptr;
+ int i;
+
+ l = line;
+ sptr = NULL;
+ for (i = 0; i < 7; i++) {
+ char *tok;
+
+ tok = strtok_r(l, " ", &sptr);
+ l = NULL;
+ if (tok == NULL)
+ /* next mountinfo line */
+ break;
+
+ if (i == 4 && strcmp(tok, "/") != 0)
+ /* next mountinfo line */
+ break;
+
+ if (i == 6) {
+ if (strncmp(tok, "shared:", 7) == 0)
+ /* there might be more / mounts, the last one counts */
+ rv = 1;
+ else
+ rv = 0;
+ }
+ }
+ }
+
+ free(line);
+ fclose(f);
+
+ return rv;
+}
static int get_user_data(struct instance_data *idata)
{
@@ -1961,12 +2027,15 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
idata.flags |= PAMNS_USE_DEFAULT_CONTEXT;
idata.flags |= PAMNS_CTXT_BASED_INST;
}
+ if (strcmp(argv[i], "mount_private") == 0) {
+ idata.flags |= PAMNS_MOUNT_PRIVATE;
+ }
if (strcmp(argv[i], "unmnt_remnt") == 0)
unmnt = UNMNT_REMNT;
if (strcmp(argv[i], "unmnt_only") == 0)
unmnt = UNMNT_ONLY;
if (strcmp(argv[i], "require_selinux") == 0) {
- if (~(idata.flags & PAMNS_SELINUX_ENABLED)) {
+ if (!(idata.flags & PAMNS_SELINUX_ENABLED)) {
pam_syslog(idata.pamh, LOG_ERR,
"selinux_required option given and selinux is disabled");
return PAM_SESSION_ERR;
@@ -1980,6 +2049,10 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
if (retval != PAM_SUCCESS)
return retval;
+ if (root_shared()) {
+ idata.flags |= PAMNS_MOUNT_PRIVATE;
+ }
+
/*
* Parse namespace configuration file which lists directories to
* polyinstantiate, directory where instance directories are to
diff --git a/modules/pam_namespace/pam_namespace.h b/modules/pam_namespace/pam_namespace.h
index da21bd70..c49995c0 100644
--- a/modules/pam_namespace/pam_namespace.h
+++ b/modules/pam_namespace/pam_namespace.h
@@ -74,6 +74,14 @@
#define CLONE_NEWNS 0x00020000 /* Flag to create new namespace */
#endif
+/* mount flags for mount_private */
+#ifndef MS_REC
+#define MS_REC (1<<14)
+#endif
+#ifndef MS_PRIVATE
+#define MS_PRIVATE (1<<18)
+#endif
+
/*
* Module defines
*/
@@ -96,6 +104,7 @@
#define PAMNS_NO_UNMOUNT_ON_CLOSE 0x00010000 /* no unmount at session close */
#define PAMNS_USE_CURRENT_CONTEXT 0x00020000 /* use getcon instead of getexeccon */
#define PAMNS_USE_DEFAULT_CONTEXT 0x00040000 /* use get_default_context instead of getexeccon */
+#define PAMNS_MOUNT_PRIVATE 0x00080000 /* Make the polydir mounts private */
/* polydir flags */
#define POLYDIR_EXCLUSIVE 0x00000001 /* polyinstatiate exclusively for override uids */