- 264 license table entries with exact download URLs (224/264 resolved) - Complete sources/ directory with all BitBake recipes - Build configuration: tqma6ul-multi-mba6ulx, spaetzle (musl) - Full traceability for Softwarefreigabeantrag - GCC 13.4.0, Linux 6.6.102, U-Boot 2023.04, musl 1.2.4 - License distribution: GPL-2.0 (24), MIT (23), GPL-2.0+ (18), BSD-3 (16)
751 lines
22 KiB
Diff
751 lines
22 KiB
Diff
From df1dab1a1a7900650ad4be157fea1a002048cc49 Mon Sep 17 00:00:00 2001
|
|
From: Olivier Bal-Petre <olivier.bal-petre@ssi.gouv.fr>
|
|
Date: Tue, 4 Mar 2025 14:37:02 +0100
|
|
Subject: [PATCH ] pam-namespace-rebase
|
|
|
|
Refresh the pam-namespace.
|
|
|
|
Upstream-Status: Backport [https://github.com/linux-pam/linux-pam/commit/a8b4dce7b53d73de372e150028c970ee0a2a2e97]
|
|
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
|
|
---
|
|
modules/pam_namespace/pam_namespace.c | 444 +++++++++++++-------------
|
|
modules/pam_namespace/pam_namespace.h | 7 +-
|
|
2 files changed, 224 insertions(+), 227 deletions(-)
|
|
|
|
diff --git a/modules/pam_namespace/pam_namespace.c b/modules/pam_namespace/pam_namespace.c
|
|
index b026861..166bfce 100644
|
|
--- a/modules/pam_namespace/pam_namespace.c
|
|
+++ b/modules/pam_namespace/pam_namespace.c
|
|
@@ -41,7 +41,7 @@
|
|
#include "pam_namespace.h"
|
|
#include "argv_parse.h"
|
|
|
|
-/* --- evaluting all files in VENDORDIR/security/namespace.d and /etc/security/namespace.d --- */
|
|
+/* --- evaluating all files in VENDORDIR/security/namespace.d and /etc/security/namespace.d --- */
|
|
static const char *base_name(const char *path)
|
|
{
|
|
const char *base = strrchr(path, '/');
|
|
@@ -55,6 +55,155 @@ compare_filename(const void *a, const void *b)
|
|
base_name(* (char * const *) b));
|
|
}
|
|
|
|
+static void close_fds_pre_exec(struct instance_data *idata)
|
|
+{
|
|
+ if (pam_modutil_sanitize_helper_fds(idata->pamh, PAM_MODUTIL_IGNORE_FD,
|
|
+ PAM_MODUTIL_IGNORE_FD, PAM_MODUTIL_IGNORE_FD) < 0) {
|
|
+ _exit(1);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+strip_trailing_slashes(char *str)
|
|
+{
|
|
+ char *p = str + strlen(str);
|
|
+
|
|
+ while (--p > str && *p == '/')
|
|
+ *p = '\0';
|
|
+}
|
|
+
|
|
+static int protect_mount(int dfd, const char *path, struct instance_data *idata)
|
|
+{
|
|
+ struct protect_dir_s *dir = idata->protect_dirs;
|
|
+ char tmpbuf[64];
|
|
+
|
|
+ while (dir != NULL) {
|
|
+ if (strcmp(path, dir->dir) == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+ dir = dir->next;
|
|
+ }
|
|
+
|
|
+ if (pam_sprintf(tmpbuf, "/proc/self/fd/%d", dfd) < 0)
|
|
+ return -1;
|
|
+
|
|
+ dir = calloc(1, sizeof(*dir));
|
|
+
|
|
+ if (dir == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ dir->dir = strdup(path);
|
|
+
|
|
+ if (dir->dir == NULL) {
|
|
+ free(dir);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (idata->flags & PAMNS_DEBUG) {
|
|
+ pam_syslog(idata->pamh, LOG_INFO,
|
|
+ "Protect mount of %s over itself", path);
|
|
+ }
|
|
+
|
|
+ if (mount(tmpbuf, tmpbuf, NULL, MS_BIND, NULL) != 0) {
|
|
+ int save_errno = errno;
|
|
+ pam_syslog(idata->pamh, LOG_ERR,
|
|
+ "Protect mount of %s failed: %m", tmpbuf);
|
|
+ free(dir->dir);
|
|
+ free(dir);
|
|
+ errno = save_errno;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ dir->next = idata->protect_dirs;
|
|
+ idata->protect_dirs = dir;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int protect_dir(const char *path, mode_t mode, int do_mkdir,
|
|
+ struct instance_data *idata)
|
|
+{
|
|
+ char *p = strdup(path);
|
|
+ char *d;
|
|
+ char *dir = p;
|
|
+ int dfd = AT_FDCWD;
|
|
+ int dfd_next;
|
|
+ int save_errno;
|
|
+ int flags = O_RDONLY | O_DIRECTORY;
|
|
+ int rv = -1;
|
|
+ struct stat st;
|
|
+
|
|
+ if (p == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (*dir == '/') {
|
|
+ dfd = open("/", flags);
|
|
+ if (dfd == -1) {
|
|
+ goto error;
|
|
+ }
|
|
+ dir++; /* assume / is safe */
|
|
+ }
|
|
+
|
|
+ while ((d=strchr(dir, '/')) != NULL) {
|
|
+ *d = '\0';
|
|
+ dfd_next = openat(dfd, dir, flags);
|
|
+ if (dfd_next == -1) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (dfd != AT_FDCWD)
|
|
+ close(dfd);
|
|
+ dfd = dfd_next;
|
|
+
|
|
+ if (fstat(dfd, &st) != 0) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (flags & O_NOFOLLOW) {
|
|
+ /* we are inside user-owned dir - protect */
|
|
+ if (protect_mount(dfd, p, idata) == -1)
|
|
+ goto error;
|
|
+ } else if (st.st_uid != 0 || st.st_gid != 0 ||
|
|
+ (st.st_mode & S_IWOTH)) {
|
|
+ /* do not follow symlinks on subdirectories */
|
|
+ flags |= O_NOFOLLOW;
|
|
+ }
|
|
+
|
|
+ *d = '/';
|
|
+ dir = d + 1;
|
|
+ }
|
|
+
|
|
+ rv = openat(dfd, dir, flags);
|
|
+
|
|
+ if (rv == -1) {
|
|
+ if (!do_mkdir || mkdirat(dfd, dir, mode) != 0) {
|
|
+ goto error;
|
|
+ }
|
|
+ rv = openat(dfd, dir, flags);
|
|
+ }
|
|
+
|
|
+ if (flags & O_NOFOLLOW) {
|
|
+ /* we are inside user-owned dir - protect */
|
|
+ if (protect_mount(rv, p, idata) == -1) {
|
|
+ save_errno = errno;
|
|
+ close(rv);
|
|
+ rv = -1;
|
|
+ errno = save_errno;
|
|
+ }
|
|
+ }
|
|
+
|
|
+error:
|
|
+ save_errno = errno;
|
|
+ free(p);
|
|
+ if (dfd != AT_FDCWD && dfd >= 0)
|
|
+ close(dfd);
|
|
+ errno = save_errno;
|
|
+
|
|
+ return rv;
|
|
+}
|
|
+
|
|
/* Evaluating a list of files which have to be parsed in the right order:
|
|
*
|
|
* - If etc/security/namespace.d/@filename@.conf exists, then
|
|
@@ -129,6 +278,7 @@ static char **read_namespace_dir(struct instance_data *idata)
|
|
return file_list;
|
|
}
|
|
|
|
+
|
|
/*
|
|
* Adds an entry for a polyinstantiated directory to the linked list of
|
|
* polyinstantiated directories. It is called from process_line() while
|
|
@@ -198,7 +348,7 @@ static void cleanup_protect_data(pam_handle_t *pamh UNUSED , void *data, int err
|
|
unprotect_dirs(data);
|
|
}
|
|
|
|
-static char *expand_variables(const char *orig, const char *var_names[], const char *var_values[])
|
|
+static char *expand_variables(const char *orig, const char *const var_names[], const char *var_values[])
|
|
{
|
|
const char *src = orig;
|
|
char *dst;
|
|
@@ -209,7 +359,7 @@ static char *expand_variables(const char *orig, const char *var_names[], const c
|
|
if (*src == '$') {
|
|
int i;
|
|
for (i = 0; var_names[i]; i++) {
|
|
- int namelen = strlen(var_names[i]);
|
|
+ size_t namelen = strlen(var_names[i]);
|
|
if (strncmp(var_names[i], src+1, namelen) == 0) {
|
|
dstlen += strlen(var_values[i]) - 1; /* $ */
|
|
src += namelen;
|
|
@@ -227,7 +377,7 @@ static char *expand_variables(const char *orig, const char *var_names[], const c
|
|
if (c == '$') {
|
|
int i;
|
|
for (i = 0; var_names[i]; i++) {
|
|
- int namelen = strlen(var_names[i]);
|
|
+ size_t namelen = strlen(var_names[i]);
|
|
if (strncmp(var_names[i], src+1, namelen) == 0) {
|
|
dst = stpcpy(dst, var_values[i]);
|
|
--dst;
|
|
@@ -311,8 +461,7 @@ static int parse_iscript_params(char *params, struct polydir_s *poly)
|
|
|
|
if (*params != '\0') {
|
|
if (*params != '/') { /* path is relative to NAMESPACE_D_DIR */
|
|
- if (asprintf(&poly->init_script, "%s%s", NAMESPACE_D_DIR, params) == -1)
|
|
- return -1;
|
|
+ poly->init_script = pam_asprintf("%s%s", NAMESPACE_D_DIR, params);
|
|
} else {
|
|
poly->init_script = strdup(params);
|
|
}
|
|
@@ -394,9 +543,9 @@ static int parse_method(char *method, struct polydir_s *poly,
|
|
{
|
|
enum polymethod pm;
|
|
char *sptr = NULL;
|
|
- static const char *method_names[] = { "user", "context", "level", "tmpdir",
|
|
+ static const char *const method_names[] = { "user", "context", "level", "tmpdir",
|
|
"tmpfs", NULL };
|
|
- static const char *flag_names[] = { "create", "noinit", "iscript",
|
|
+ static const char *const flag_names[] = { "create", "noinit", "iscript",
|
|
"shared", "mntopts", NULL };
|
|
static const unsigned int flag_values[] = { POLYDIR_CREATE, POLYDIR_NOINIT,
|
|
POLYDIR_ISCRIPT, POLYDIR_SHARED, POLYDIR_MNTOPTS };
|
|
@@ -421,7 +570,7 @@ static int parse_method(char *method, struct polydir_s *poly,
|
|
|
|
while ((flag=strtok_r(NULL, ":", &sptr)) != NULL) {
|
|
for (i = 0; flag_names[i]; i++) {
|
|
- int namelen = strlen(flag_names[i]);
|
|
+ size_t namelen = strlen(flag_names[i]);
|
|
|
|
if (strncmp(flag, flag_names[i], namelen) == 0) {
|
|
poly->flags |= flag_values[i];
|
|
@@ -467,27 +616,27 @@ static int parse_method(char *method, struct polydir_s *poly,
|
|
* of the namespace configuration file. It skips over comments and incomplete
|
|
* or malformed lines. It processes a valid line with information on
|
|
* polyinstantiating a directory by populating appropriate fields of a
|
|
- * polyinstatiated directory structure and then calling add_polydir_entry to
|
|
+ * polyinstantiated directory structure and then calling add_polydir_entry to
|
|
* add that entry to the linked list of polyinstantiated directories.
|
|
*/
|
|
static int process_line(char *line, const char *home, const char *rhome,
|
|
struct instance_data *idata)
|
|
{
|
|
char *dir = NULL, *instance_prefix = NULL, *rdir = NULL;
|
|
+ const char *config_dir, *config_instance_prefix;
|
|
char *method, *uids;
|
|
char *tptr;
|
|
struct polydir_s *poly;
|
|
int retval = 0;
|
|
char **config_options = NULL;
|
|
- static const char *var_names[] = {"HOME", "USER", NULL};
|
|
+ static const char *const var_names[] = {"HOME", "USER", NULL};
|
|
const char *var_values[] = {home, idata->user};
|
|
const char *rvar_values[] = {rhome, idata->ruser};
|
|
- int len;
|
|
|
|
/*
|
|
* skip the leading white space
|
|
*/
|
|
- while (*line && isspace(*line))
|
|
+ while (*line && isspace((unsigned char)*line))
|
|
line++;
|
|
|
|
/*
|
|
@@ -523,22 +672,19 @@ static int process_line(char *line, const char *home, const char *rhome,
|
|
goto erralloc;
|
|
}
|
|
|
|
- dir = config_options[0];
|
|
- if (dir == NULL) {
|
|
+ config_dir = config_options[0];
|
|
+ if (config_dir == NULL) {
|
|
pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing polydir");
|
|
goto skipping;
|
|
}
|
|
- instance_prefix = config_options[1];
|
|
- if (instance_prefix == NULL) {
|
|
+ config_instance_prefix = config_options[1];
|
|
+ if (config_instance_prefix == NULL) {
|
|
pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing instance_prefix");
|
|
- instance_prefix = NULL;
|
|
goto skipping;
|
|
}
|
|
method = config_options[2];
|
|
if (method == NULL) {
|
|
pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing method");
|
|
- instance_prefix = NULL;
|
|
- dir = NULL;
|
|
goto skipping;
|
|
}
|
|
|
|
@@ -553,19 +699,16 @@ static int process_line(char *line, const char *home, const char *rhome,
|
|
/*
|
|
* Expand $HOME and $USER in poly dir and instance dir prefix
|
|
*/
|
|
- if ((rdir=expand_variables(dir, var_names, rvar_values)) == NULL) {
|
|
- instance_prefix = NULL;
|
|
- dir = NULL;
|
|
+ if ((rdir = expand_variables(config_dir, var_names, rvar_values)) == NULL) {
|
|
goto erralloc;
|
|
}
|
|
|
|
- if ((dir=expand_variables(dir, var_names, var_values)) == NULL) {
|
|
- instance_prefix = NULL;
|
|
+ if ((dir = expand_variables(config_dir, var_names, var_values)) == NULL) {
|
|
goto erralloc;
|
|
}
|
|
|
|
- if ((instance_prefix=expand_variables(instance_prefix, var_names, var_values))
|
|
- == NULL) {
|
|
+ if ((instance_prefix = expand_variables(config_instance_prefix,
|
|
+ var_names, var_values)) == NULL) {
|
|
goto erralloc;
|
|
}
|
|
|
|
@@ -575,15 +718,8 @@ static int process_line(char *line, const char *home, const char *rhome,
|
|
pam_syslog(idata->pamh, LOG_DEBUG, "Expanded instance prefix: '%s'", instance_prefix);
|
|
}
|
|
|
|
- len = strlen(dir);
|
|
- if (len > 0 && dir[len-1] == '/') {
|
|
- dir[len-1] = '\0';
|
|
- }
|
|
-
|
|
- len = strlen(rdir);
|
|
- if (len > 0 && rdir[len-1] == '/') {
|
|
- rdir[len-1] = '\0';
|
|
- }
|
|
+ strip_trailing_slashes(dir);
|
|
+ strip_trailing_slashes(rdir);
|
|
|
|
if (dir[0] == '\0' || rdir[0] == '\0') {
|
|
pam_syslog(idata->pamh, LOG_NOTICE, "Invalid polydir");
|
|
@@ -594,26 +730,19 @@ static int process_line(char *line, const char *home, const char *rhome,
|
|
* Populate polyinstantiated directory structure with appropriate
|
|
* pathnames and the method with which to polyinstantiate.
|
|
*/
|
|
- if (strlen(dir) >= sizeof(poly->dir)
|
|
- || strlen(rdir) >= sizeof(poly->rdir)
|
|
- || strlen(instance_prefix) >= sizeof(poly->instance_prefix)) {
|
|
- pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long");
|
|
- goto skipping;
|
|
- }
|
|
- strcpy(poly->dir, dir);
|
|
- strcpy(poly->rdir, rdir);
|
|
- strcpy(poly->instance_prefix, instance_prefix);
|
|
-
|
|
if (parse_method(method, poly, idata) != 0) {
|
|
goto skipping;
|
|
}
|
|
|
|
- if (poly->method == TMPDIR) {
|
|
- if (sizeof(poly->instance_prefix) - strlen(poly->instance_prefix) < 7) {
|
|
- pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long");
|
|
- goto skipping;
|
|
- }
|
|
- strcat(poly->instance_prefix, "XXXXXX");
|
|
+#define COPY_STR(dst, src, apd) \
|
|
+ pam_sprintf((dst), "%s%s", (src), (apd))
|
|
+
|
|
+ if (COPY_STR(poly->dir, dir, "") < 0
|
|
+ || COPY_STR(poly->rdir, rdir, "") < 0
|
|
+ || COPY_STR(poly->instance_prefix, instance_prefix,
|
|
+ poly->method == TMPDIR ? "XXXXXX" : "") < 0) {
|
|
+ pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long");
|
|
+ goto skipping;
|
|
}
|
|
|
|
/*
|
|
@@ -637,7 +766,7 @@ static int process_line(char *line, const char *home, const char *rhome,
|
|
if (uids) {
|
|
uid_t *uidptr;
|
|
const char *ustr, *sstr;
|
|
- int count, i;
|
|
+ size_t count, i;
|
|
|
|
if (*uids == '~') {
|
|
poly->flags |= POLYDIR_EXCLUSIVE;
|
|
@@ -646,8 +775,13 @@ static int process_line(char *line, const char *home, const char *rhome,
|
|
for (count = 0, ustr = sstr = uids; sstr; ustr = sstr + 1, count++)
|
|
sstr = strchr(ustr, ',');
|
|
|
|
+ if (count > UINT_MAX || count > SIZE_MAX / sizeof(uid_t)) {
|
|
+ pam_syslog(idata->pamh, LOG_ERR, "Too many uids encountered in configuration");
|
|
+ goto skipping;
|
|
+ }
|
|
+
|
|
poly->num_uids = count;
|
|
- poly->uid = (uid_t *) malloc(count * sizeof (uid_t));
|
|
+ poly->uid = malloc(count * sizeof (uid_t));
|
|
uidptr = poly->uid;
|
|
if (uidptr == NULL) {
|
|
goto erralloc;
|
|
@@ -996,6 +1130,7 @@ static int form_context(const struct polydir_s *polyptr,
|
|
return rc;
|
|
}
|
|
/* Should never get here */
|
|
+ freecon(scon);
|
|
return PAM_SUCCESS;
|
|
}
|
|
#endif
|
|
@@ -1057,10 +1192,8 @@ static int poly_name(const struct polydir_s *polyptr, char **i_name,
|
|
|
|
switch (pm) {
|
|
case USER:
|
|
- if (asprintf(i_name, "%s", idata->user) < 0) {
|
|
- *i_name = NULL;
|
|
+ if ((*i_name = strdup(idata->user)) == NULL)
|
|
goto fail;
|
|
- }
|
|
break;
|
|
|
|
#ifdef WITH_SELINUX
|
|
@@ -1070,17 +1203,12 @@ static int poly_name(const struct polydir_s *polyptr, char **i_name,
|
|
pam_syslog(idata->pamh, LOG_ERR, "Error translating directory context");
|
|
goto fail;
|
|
}
|
|
- if (polyptr->flags & POLYDIR_SHARED) {
|
|
- if (asprintf(i_name, "%s", rawcon) < 0) {
|
|
- *i_name = NULL;
|
|
- goto fail;
|
|
- }
|
|
- } else {
|
|
- if (asprintf(i_name, "%s_%s", rawcon, idata->user) < 0) {
|
|
- *i_name = NULL;
|
|
- goto fail;
|
|
- }
|
|
- }
|
|
+ if (polyptr->flags & POLYDIR_SHARED)
|
|
+ *i_name = strdup(rawcon);
|
|
+ else
|
|
+ *i_name = pam_asprintf("%s_%s", rawcon, idata->user);
|
|
+ if (*i_name == NULL)
|
|
+ goto fail;
|
|
break;
|
|
|
|
#endif /* WITH_SELINUX */
|
|
@@ -1110,11 +1238,12 @@ static int poly_name(const struct polydir_s *polyptr, char **i_name,
|
|
*i_name = hash;
|
|
hash = NULL;
|
|
} else {
|
|
- char *newname;
|
|
- if (asprintf(&newname, "%.*s_%s", NAMESPACE_MAX_DIR_LEN-1-(int)strlen(hash),
|
|
- *i_name, hash) < 0) {
|
|
+ char *newname =
|
|
+ pam_asprintf("%.*s_%s",
|
|
+ NAMESPACE_MAX_DIR_LEN - 1 - (int)strlen(hash),
|
|
+ *i_name, hash);
|
|
+ if (newname == NULL)
|
|
goto fail;
|
|
- }
|
|
free(*i_name);
|
|
*i_name = newname;
|
|
}
|
|
@@ -1139,137 +1268,6 @@ fail:
|
|
return rc;
|
|
}
|
|
|
|
-static int protect_mount(int dfd, const char *path, struct instance_data *idata)
|
|
-{
|
|
- struct protect_dir_s *dir = idata->protect_dirs;
|
|
- char tmpbuf[64];
|
|
-
|
|
- while (dir != NULL) {
|
|
- if (strcmp(path, dir->dir) == 0) {
|
|
- return 0;
|
|
- }
|
|
- dir = dir->next;
|
|
- }
|
|
-
|
|
- dir = calloc(1, sizeof(*dir));
|
|
-
|
|
- if (dir == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
- dir->dir = strdup(path);
|
|
-
|
|
- if (dir->dir == NULL) {
|
|
- free(dir);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- snprintf(tmpbuf, sizeof(tmpbuf), "/proc/self/fd/%d", dfd);
|
|
-
|
|
- if (idata->flags & PAMNS_DEBUG) {
|
|
- pam_syslog(idata->pamh, LOG_INFO,
|
|
- "Protect mount of %s over itself", path);
|
|
- }
|
|
-
|
|
- if (mount(tmpbuf, tmpbuf, NULL, MS_BIND, NULL) != 0) {
|
|
- int save_errno = errno;
|
|
- pam_syslog(idata->pamh, LOG_ERR,
|
|
- "Protect mount of %s failed: %m", tmpbuf);
|
|
- free(dir->dir);
|
|
- free(dir);
|
|
- errno = save_errno;
|
|
- return -1;
|
|
- }
|
|
-
|
|
- dir->next = idata->protect_dirs;
|
|
- idata->protect_dirs = dir;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int protect_dir(const char *path, mode_t mode, int do_mkdir,
|
|
- struct instance_data *idata)
|
|
-{
|
|
- char *p = strdup(path);
|
|
- char *d;
|
|
- char *dir = p;
|
|
- int dfd = AT_FDCWD;
|
|
- int dfd_next;
|
|
- int save_errno;
|
|
- int flags = O_RDONLY | O_DIRECTORY;
|
|
- int rv = -1;
|
|
- struct stat st;
|
|
-
|
|
- if (p == NULL) {
|
|
- goto error;
|
|
- }
|
|
-
|
|
- if (*dir == '/') {
|
|
- dfd = open("/", flags);
|
|
- if (dfd == -1) {
|
|
- goto error;
|
|
- }
|
|
- dir++; /* assume / is safe */
|
|
- }
|
|
-
|
|
- while ((d=strchr(dir, '/')) != NULL) {
|
|
- *d = '\0';
|
|
- dfd_next = openat(dfd, dir, flags);
|
|
- if (dfd_next == -1) {
|
|
- goto error;
|
|
- }
|
|
-
|
|
- if (dfd != AT_FDCWD)
|
|
- close(dfd);
|
|
- dfd = dfd_next;
|
|
-
|
|
- if (fstat(dfd, &st) != 0) {
|
|
- goto error;
|
|
- }
|
|
-
|
|
- if (flags & O_NOFOLLOW) {
|
|
- /* we are inside user-owned dir - protect */
|
|
- if (protect_mount(dfd, p, idata) == -1)
|
|
- goto error;
|
|
- } else if (st.st_uid != 0 || st.st_gid != 0 ||
|
|
- (st.st_mode & S_IWOTH)) {
|
|
- /* do not follow symlinks on subdirectories */
|
|
- flags |= O_NOFOLLOW;
|
|
- }
|
|
-
|
|
- *d = '/';
|
|
- dir = d + 1;
|
|
- }
|
|
-
|
|
- rv = openat(dfd, dir, flags);
|
|
-
|
|
- if (rv == -1) {
|
|
- if (!do_mkdir || mkdirat(dfd, dir, mode) != 0) {
|
|
- goto error;
|
|
- }
|
|
- rv = openat(dfd, dir, flags);
|
|
- }
|
|
-
|
|
- if (flags & O_NOFOLLOW) {
|
|
- /* we are inside user-owned dir - protect */
|
|
- if (protect_mount(rv, p, idata) == -1) {
|
|
- save_errno = errno;
|
|
- close(rv);
|
|
- rv = -1;
|
|
- errno = save_errno;
|
|
- }
|
|
- }
|
|
-
|
|
-error:
|
|
- save_errno = errno;
|
|
- free(p);
|
|
- if (dfd != AT_FDCWD && dfd >= 0)
|
|
- close(dfd);
|
|
- errno = save_errno;
|
|
-
|
|
- return rv;
|
|
-}
|
|
-
|
|
static int check_inst_parent(char *ipath, struct instance_data *idata)
|
|
{
|
|
struct stat instpbuf;
|
|
@@ -1281,13 +1279,12 @@ static int check_inst_parent(char *ipath, struct instance_data *idata)
|
|
* admin explicitly instructs to ignore the instance parent
|
|
* mode by the "ignore_instance_parent_mode" argument).
|
|
*/
|
|
- inst_parent = (char *) malloc(strlen(ipath)+1);
|
|
+ inst_parent = strdup(ipath);
|
|
if (!inst_parent) {
|
|
pam_syslog(idata->pamh, LOG_CRIT, "Error allocating pathname string");
|
|
return PAM_SESSION_ERR;
|
|
}
|
|
|
|
- strcpy(inst_parent, ipath);
|
|
trailing_slash = strrchr(inst_parent, '/');
|
|
if (trailing_slash)
|
|
*trailing_slash = '\0';
|
|
@@ -1371,9 +1368,10 @@ static int inst_init(const struct polydir_s *polyptr, const char *ipath,
|
|
if (setuid(geteuid()) < 0) {
|
|
/* ignore failures, they don't matter */
|
|
}
|
|
+ close_fds_pre_exec(idata);
|
|
|
|
- if (execle(init_script, init_script,
|
|
- polyptr->dir, ipath, newdir?"1":"0", idata->user, NULL, envp) < 0)
|
|
+ execle(init_script, init_script,
|
|
+ polyptr->dir, ipath, newdir?"1":"0", idata->user, NULL, envp);
|
|
_exit(1);
|
|
} else if (pid > 0) {
|
|
while (((rc = waitpid(pid, &status, 0)) == (pid_t)-1) &&
|
|
@@ -1424,7 +1422,9 @@ static int create_polydir(struct polydir_s *polyptr,
|
|
|
|
#ifdef WITH_SELINUX
|
|
if (idata->flags & PAMNS_SELINUX_ENABLED) {
|
|
- getfscreatecon_raw(&oldcon_raw);
|
|
+ if (getfscreatecon_raw(&oldcon_raw) != 0)
|
|
+ pam_syslog(idata->pamh, LOG_NOTICE,
|
|
+ "Error retrieving fs create context: %m");
|
|
|
|
label_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
|
|
if (!label_handle) {
|
|
@@ -1453,6 +1453,9 @@ static int create_polydir(struct polydir_s *polyptr,
|
|
if (rc == -1) {
|
|
pam_syslog(idata->pamh, LOG_ERR,
|
|
"Error creating directory %s: %m", dir);
|
|
+#ifdef WITH_SELINUX
|
|
+ freecon(oldcon_raw);
|
|
+#endif
|
|
return PAM_SESSION_ERR;
|
|
}
|
|
|
|
@@ -1640,16 +1643,14 @@ static int ns_setup(struct polydir_s *polyptr,
|
|
|
|
retval = protect_dir(polyptr->dir, 0, 0, idata);
|
|
|
|
- if (retval < 0 && errno != ENOENT) {
|
|
- pam_syslog(idata->pamh, LOG_ERR, "Polydir %s access error: %m",
|
|
- polyptr->dir);
|
|
- return PAM_SESSION_ERR;
|
|
- }
|
|
-
|
|
if (retval < 0) {
|
|
- if ((polyptr->flags & POLYDIR_CREATE) &&
|
|
- create_polydir(polyptr, idata) != PAM_SUCCESS)
|
|
- return PAM_SESSION_ERR;
|
|
+ if (errno != ENOENT || !(polyptr->flags & POLYDIR_CREATE)) {
|
|
+ pam_syslog(idata->pamh, LOG_ERR, "Polydir %s access error: %m",
|
|
+ polyptr->dir);
|
|
+ return PAM_SESSION_ERR;
|
|
+ }
|
|
+ if (create_polydir(polyptr, idata) != PAM_SUCCESS)
|
|
+ return PAM_SESSION_ERR;
|
|
} else {
|
|
close(retval);
|
|
}
|
|
@@ -1698,7 +1699,7 @@ static int ns_setup(struct polydir_s *polyptr,
|
|
#endif
|
|
}
|
|
|
|
- if (asprintf(&inst_dir, "%s%s", polyptr->instance_prefix, instname) < 0)
|
|
+ if ((inst_dir = pam_asprintf("%s%s", polyptr->instance_prefix, instname)) == NULL)
|
|
goto error_out;
|
|
|
|
if (idata->flags & PAMNS_DEBUG)
|
|
@@ -1810,8 +1811,9 @@ static int cleanup_tmpdirs(struct instance_data *idata)
|
|
_exit(1);
|
|
}
|
|
#endif
|
|
- if (execle("/bin/rm", "/bin/rm", "-rf", pptr->instance_prefix, NULL, envp) < 0)
|
|
- _exit(1);
|
|
+ close_fds_pre_exec(idata);
|
|
+ execle("/bin/rm", "/bin/rm", "-rf", pptr->instance_prefix, NULL, envp);
|
|
+ _exit(1);
|
|
} else if (pid > 0) {
|
|
while (((rc = waitpid(pid, &status, 0)) == (pid_t)-1) &&
|
|
(errno == EINTR));
|
|
@@ -1826,7 +1828,7 @@ static int cleanup_tmpdirs(struct instance_data *idata)
|
|
}
|
|
} else if (pid < 0) {
|
|
pam_syslog(idata->pamh, LOG_ERR,
|
|
- "Cannot fork to run namespace init script, %m");
|
|
+ "Cannot fork to cleanup temporary directory, %m");
|
|
rc = PAM_SESSION_ERR;
|
|
goto out;
|
|
}
|
|
diff --git a/modules/pam_namespace/pam_namespace.h b/modules/pam_namespace/pam_namespace.h
|
|
index a991b4c..180e042 100644
|
|
--- a/modules/pam_namespace/pam_namespace.h
|
|
+++ b/modules/pam_namespace/pam_namespace.h
|
|
@@ -44,21 +44,16 @@
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <syslog.h>
|
|
-#include <dlfcn.h>
|
|
-#include <stdarg.h>
|
|
#include <pwd.h>
|
|
#include <grp.h>
|
|
#include <limits.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
-#include <sys/resource.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/wait.h>
|
|
-#include <libgen.h>
|
|
#include <fcntl.h>
|
|
#include <sched.h>
|
|
#include <glob.h>
|
|
-#include <locale.h>
|
|
#include "security/pam_modules.h"
|
|
#include "security/pam_modutil.h"
|
|
#include "security/pam_ext.h"
|
|
@@ -114,7 +109,7 @@
|
|
#define PAMNS_MOUNT_PRIVATE 0x00080000 /* Make the polydir mounts private */
|
|
|
|
/* polydir flags */
|
|
-#define POLYDIR_EXCLUSIVE 0x00000001 /* polyinstatiate exclusively for override uids */
|
|
+#define POLYDIR_EXCLUSIVE 0x00000001 /* polyinstantiate exclusively for override uids */
|
|
#define POLYDIR_CREATE 0x00000002 /* create the polydir */
|
|
#define POLYDIR_NOINIT 0x00000004 /* no init script */
|
|
#define POLYDIR_SHARED 0x00000008 /* share context/level instances among users */
|
|
--
|
|
2.49.0
|
|
|