xref: /OK3568_Linux_fs/yocto/poky/meta/recipes-extended/pam/libpam/CVE-2022-28321-0002.patch (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1From 23393bef92c1e768eda329813d7af55481c6ca9f Mon Sep 17 00:00:00 2001
2From: Thorsten Kukuk <kukuk@suse.com>
3Date: Thu, 24 Feb 2022 10:37:32 +0100
4Subject: [PATCH 2/2] pam_access: handle hostnames in access.conf
5
6According to the manual page, the following entry is valid but does not
7work:
8-:root:ALL EXCEPT localhost
9
10See https://bugzilla.suse.com/show_bug.cgi?id=1019866
11
12Patched is based on PR#226 from Josef Moellers
13
14Upstream-Status: Backport
15CVE: CVE-2022-28321
16
17Reference to upstream patch:
18[https://github.com/linux-pam/linux-pam/commit/23393bef92c1e768eda329813d7af55481c6ca9f]
19
20Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com>
21---
22 modules/pam_access/pam_access.c | 95 ++++++++++++++++++++++++++-------
23 1 file changed, 76 insertions(+), 19 deletions(-)
24
25diff --git a/modules/pam_access/pam_access.c b/modules/pam_access/pam_access.c
26index 277192b..bca424f 100644
27--- a/modules/pam_access/pam_access.c
28+++ b/modules/pam_access/pam_access.c
29@@ -637,7 +637,7 @@ remote_match (pam_handle_t *pamh, char *tok, struct login_info *item)
30       if ((str_len = strlen(string)) > tok_len
31 	  && strcasecmp(tok, string + str_len - tok_len) == 0)
32 	return YES;
33-    } else if (tok[tok_len - 1] == '.') {
34+    } else if (tok[tok_len - 1] == '.') {       /* internet network numbers (end with ".") */
35       struct addrinfo hint;
36
37       memset (&hint, '\0', sizeof (hint));
38@@ -678,7 +678,7 @@ remote_match (pam_handle_t *pamh, char *tok, struct login_info *item)
39       return NO;
40     }
41
42-    /* Assume network/netmask with an IP of a host.  */
43+    /* Assume network/netmask, IP address or hostname.  */
44     return network_netmask_match(pamh, tok, string, item);
45 }
46
47@@ -696,7 +696,7 @@ string_match (pam_handle_t *pamh, const char *tok, const char *string,
48     /*
49      * If the token has the magic value "ALL" the match always succeeds.
50      * Otherwise, return YES if the token fully matches the string.
51-	 * "NONE" token matches NULL string.
52+     * "NONE" token matches NULL string.
53      */
54
55     if (strcasecmp(tok, "ALL") == 0) {		/* all: always matches */
56@@ -714,7 +714,8 @@ string_match (pam_handle_t *pamh, const char *tok, const char *string,
57
58 /* network_netmask_match - match a string against one token
59  * where string is a hostname or ip (v4,v6) address and tok
60- * represents either a single ip (v4,v6) address or a network/netmask
61+ * represents either a hostname, a single ip (v4,v6) address
62+ * or a network/netmask
63  */
64 static int
65 network_netmask_match (pam_handle_t *pamh,
66@@ -723,10 +724,12 @@ network_netmask_match (pam_handle_t *pamh,
67     char *netmask_ptr;
68     char netmask_string[MAXHOSTNAMELEN + 1];
69     int addr_type;
70+    struct addrinfo *ai = NULL;
71
72     if (item->debug)
73-    pam_syslog (pamh, LOG_DEBUG,
74+      pam_syslog (pamh, LOG_DEBUG,
75 		"network_netmask_match: tok=%s, item=%s", tok, string);
76+
77     /* OK, check if tok is of type addr/mask */
78     if ((netmask_ptr = strchr(tok, '/')) != NULL)
79       {
80@@ -760,54 +763,108 @@ network_netmask_match (pam_handle_t *pamh,
81 	    netmask_ptr = number_to_netmask(netmask, addr_type,
82 		netmask_string, MAXHOSTNAMELEN);
83 	  }
84-	}
85+
86+        /*
87+         * Construct an addrinfo list from the IP address.
88+         * This should not fail as the input is a correct IP address...
89+         */
90+	if (getaddrinfo (tok, NULL, NULL, &ai) != 0)
91+	  {
92+	    return NO;
93+	  }
94+      }
95     else
96-	/* NO, then check if it is only an addr */
97-	if (isipaddr(tok, NULL, NULL) != YES)
98+      {
99+        /*
100+	 * It is either an IP address or a hostname.
101+	 * Let getaddrinfo sort everything out
102+	 */
103+	if (getaddrinfo (tok, NULL, NULL, &ai) != 0)
104 	  {
105+	    pam_syslog(pamh, LOG_ERR, "cannot resolve hostname \"%s\"", tok);
106+
107 	    return NO;
108 	  }
109+	netmask_ptr = NULL;
110+      }
111
112     if (isipaddr(string, NULL, NULL) != YES)
113       {
114-	/* Assume network/netmask with a name of a host.  */
115 	struct addrinfo hint;
116
117+	/* Assume network/netmask with a name of a host.  */
118 	memset (&hint, '\0', sizeof (hint));
119 	hint.ai_flags = AI_CANONNAME;
120 	hint.ai_family = AF_UNSPEC;
121
122 	if (item->gai_rv != 0)
123+	  {
124+	    freeaddrinfo(ai);
125 	    return NO;
126+	  }
127 	else if (!item->res &&
128 		(item->gai_rv = getaddrinfo (string, NULL, &hint, &item->res)) != 0)
129+	  {
130+	    freeaddrinfo(ai);
131 	    return NO;
132+	  }
133         else
134 	  {
135 	    struct addrinfo *runp = item->res;
136+	    struct addrinfo *runp1;
137
138 	    while (runp != NULL)
139 	      {
140 		char buf[INET6_ADDRSTRLEN];
141
142-		DIAG_PUSH_IGNORE_CAST_ALIGN;
143-		inet_ntop (runp->ai_family,
144-			runp->ai_family == AF_INET
145-			? (void *) &((struct sockaddr_in *) runp->ai_addr)->sin_addr
146-			: (void *) &((struct sockaddr_in6 *) runp->ai_addr)->sin6_addr,
147-			buf, sizeof (buf));
148-		DIAG_POP_IGNORE_CAST_ALIGN;
149+		if (getnameinfo (runp->ai_addr, runp->ai_addrlen, buf, sizeof (buf), NULL, 0, NI_NUMERICHOST) != 0)
150+		  {
151+		    freeaddrinfo(ai);
152+		    return NO;
153+		  }
154
155-		if (are_addresses_equal(buf, tok, netmask_ptr))
156+		for (runp1 = ai; runp1 != NULL; runp1 = runp1->ai_next)
157 		  {
158-		    return YES;
159+                    char buf1[INET6_ADDRSTRLEN];
160+
161+                    if (runp->ai_family != runp1->ai_family)
162+                      continue;
163+
164+                    if (getnameinfo (runp1->ai_addr, runp1->ai_addrlen, buf1, sizeof (buf1), NULL, 0, NI_NUMERICHOST) != 0)
165+		      {
166+			freeaddrinfo(ai);
167+			return NO;
168+		      }
169+
170+                    if (are_addresses_equal (buf, buf1, netmask_ptr))
171+                      {
172+                        freeaddrinfo(ai);
173+                        return YES;
174+                      }
175 		  }
176 		runp = runp->ai_next;
177 	      }
178 	  }
179       }
180     else
181-      return (are_addresses_equal(string, tok, netmask_ptr));
182+      {
183+       struct addrinfo *runp1;
184+
185+       for (runp1 = ai; runp1 != NULL; runp1 = runp1->ai_next)
186+         {
187+           char buf1[INET6_ADDRSTRLEN];
188+
189+           (void) getnameinfo (runp1->ai_addr, runp1->ai_addrlen, buf1, sizeof (buf1), NULL, 0, NI_NUMERICHOST);
190+
191+           if (are_addresses_equal(string, buf1, netmask_ptr))
192+             {
193+               freeaddrinfo(ai);
194+               return YES;
195+             }
196+         }
197+      }
198+
199+  freeaddrinfo(ai);
200
201   return NO;
202 }
203--
2042.37.3
205
206