diff -up Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.c.private Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.c --- Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.c.private 2010-10-22 09:41:09.000000000 +0200 +++ Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.c 2011-06-07 17:28:04.000000000 +0200 @@ -61,9 +61,11 @@ static void add_polydir_entry(struct ins 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, cons 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, cons 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 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, } } - 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, 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 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 } #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 *po 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 *po 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 *po 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_h 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_h 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 -up Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.h.private Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.h --- Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.h.private 2008-04-18 14:53:38.000000000 +0200 +++ Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.h 2011-06-07 17:26:25.000000000 +0200 @@ -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 */ diff -up Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.8.xml.private Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.8.xml --- Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.8.xml.private 2009-06-01 09:03:20.000000000 +0200 +++ Linux-PAM-1.1.3/modules/pam_namespace/pam_namespace.8.xml 2011-06-07 17:26:12.000000000 +0200 @@ -52,6 +52,9 @@ use_default_context + + mount_private + @@ -234,6 +237,24 @@ + + + + + + + This option can be used on systems where the / mount point or + its submounts are made shared (for example with a + mount --make-rshared / 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. + + + +