[Pam-developers] [PATCH] pam_loginuid: Ignore failure in user namespaces (v2)

Stéphane Graber stgraber at ubuntu.com
Tue Jan 7 23:45:10 UTC 2014


When running pam_loginuid in a container using the user namespaces, even
uid 0 isn't allowed to set the loginuid property.

This change catches the EACCES from opening loginuid, checks if the user
is in the host namespace (by comparing the uid_map with the host's one)
and only if that's the case, sets rc to 1.

Should uid_map not exist to be unreadable for some reason, it'll be
assumed that the process is running on the host's namespace.

The initial reason behind this change was failure to ssh into an
unprivileged container (using a 3.13 kernel and current LXC) when using
a standard pam profile for sshd (which requires success from
pam_loginuid).

I believe this solution doesn't have any drawback and will allow people
to use unprivileged containers normally. An alternative would be to have
all distros set pam_loginuid as optional but that'd be bad for any of
the other potential failure case which people may care about.

There has also been some discussions to get some of the audit features
tied with the user namespaces but currently none of that has been merged
upstream and the currently proposed implementation doesn't cover
loginuid (nor is it clear how this should even work when loginuid is set
as immutable after initial write).
---
 modules/pam_loginuid/pam_loginuid.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c
index a903845..60f11f7 100644
--- a/modules/pam_loginuid/pam_loginuid.c
+++ b/modules/pam_loginuid/pam_loginuid.c
@@ -47,18 +47,33 @@
 
 /*
  * This function writes the loginuid to the /proc system. It returns
- * 0 on success and 1 on failure.
+ * the relevant PAM return value.
  */
 static int set_loginuid(pam_handle_t *pamh, uid_t uid)
 {
-	int fd, count, rc = 0;
+	int fd, count, rc = PAM_SUCCESS;
 	char loginuid[24], buf[24];
+	char uid_map[256];
 
 	count = snprintf(loginuid, sizeof(loginuid), "%lu", (unsigned long)uid);
 	fd = open("/proc/self/loginuid", O_NOFOLLOW|O_RDWR);
 	if (fd < 0) {
-		if (errno != ENOENT) {
-			rc = 1;
+		if (errno == EACCES) {
+			rc = PAM_SESSION_ERR;
+			fd = open("/proc/self/uid_map", O_RDONLY);
+			if (fd >= 0) {
+				count = pam_modutil_read(fd, uid_map, sizeof(uid_map));
+				if (strncmp(uid_map, "         0          0 4294967295\n",
+				    count) != 0)
+					rc = PAM_IGNORE;
+				close(fd);
+			}
+			if (rc == PAM_IGNORE)
+				pam_syslog(pamh, LOG_ERR,
+					   "Cannot open /proc/self/loginuid: Permission denied");
+		}
+		else if (errno != ENOENT) {
+			rc = PAM_IGNORE;
 			pam_syslog(pamh, LOG_ERR,
 				   "Cannot open /proc/self/loginuid: %m");
 		}
@@ -69,7 +84,7 @@ static int set_loginuid(pam_handle_t *pamh, uid_t uid)
 		goto done;	/* already correct */
 	if (lseek(fd, 0, SEEK_SET) == -1 || (ftruncate(fd, 0) == -1 ||
 	    pam_modutil_write(fd, loginuid, count) != count))
-		rc = 1;
+		rc = PAM_SESSION_ERR;
  done:
 	close(fd);
 	return rc;
@@ -170,6 +185,7 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED,
 {
         const char *user = NULL;
 	struct passwd *pwd;
+	int ret;
 #ifdef HAVE_LIBAUDIT
 	int require_auditd = 0;
 #endif
@@ -188,9 +204,10 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED,
 		return PAM_SESSION_ERR;
 	}
 
-	if (set_loginuid(pamh, pwd->pw_uid)) {
+	ret = set_loginuid(pamh, pwd->pw_uid);
+	if (ret != PAM_SUCCESS) {
 		pam_syslog(pamh, LOG_ERR, "set_loginuid failed\n");
-		return PAM_SESSION_ERR;
+		return ret;
 	}
 
 #ifdef HAVE_LIBAUDIT
-- 
1.8.5.2



More information about the Pam-developers mailing list