summaryrefslogtreecommitdiff
blob: c245cb78dcbc6a321dad71ad03389deee9062f8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
From bf84fd00d3ac1ae2a43dac57f7ef689ef2e8b8aa Mon Sep 17 00:00:00 2001
From: Nils Freydank <holgersson@posteo.de>
Date: Fri, 20 Oct 2017 22:30:33 +0200
Subject: [PATCH] Fix CVE-2016-5434 (DoS/loop and out of boundary read)

This is a rewrite of Tobias Stoeckmann’s patch from June 2016[1] using
functions instead of macros. (Thanks to Tobias for explanations of his patch.)
A short question on Freenode IRC showed that macros are generally discouraged
and functions should be used.

The patch introduces a static size_t length_check() in libalpm/signing.c.

[1] Original patch:
https://lists.archlinux.org/pipermail/pacman-dev/2016-June/021148.html
CVE request (and assignment):
http://seclists.org/oss-sec/2016/q2/526
---
 This patch is provided to upstream, but not merged (2017-10-25).

 lib/libalpm/signing.c | 48 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 44 insertions(+), 4 deletions(-)

diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c
index 95cb3280..51b11df6 100644
--- a/lib/libalpm/signing.c
+++ b/lib/libalpm/signing.c
@@ -986,6 +986,19 @@ int SYMEXPORT alpm_siglist_cleanup(alpm_siglist_t *siglist)
 	return 0;
 }
 
+/* Check to avoid out of boundary reads */
+static size_t length_check(size_t length, size_t position, size_t a,
+		alpm_handle_t *handle, const char *identifier)
+{
+	if( a == 0 || length - position <= a) {
+		_alpm_log(handle, ALPM_LOG_ERROR,
+		_("%s: signature format error"), identifier);
+		return -1;
+	} else {
+		return 0;
+	}
+}
+
 /**
  * Extract the Issuer Key ID from a signature
  * @param sig PGP signature
@@ -1022,16 +1035,25 @@ int SYMEXPORT alpm_extract_keyid(alpm_handle_t *handle, const char *identifier,
 
 		switch(sig[pos] & 0x03) {
 			case 0:
+				if(length_check(len, pos, 2, handle, identifier) != 0) {
+					return -1;
+				}
 				blen = sig[pos + 1];
 				pos = pos + 2;
 				break;
 
 			case 1:
+				if(length_check(len, pos, 3, handle, identifier)) {
+					return -1;
+				}
 				blen = (sig[pos + 1] << 8) | sig[pos + 2];
 				pos = pos + 3;
 				break;
 
 			case 2:
+				if(length_check(len, pos, 5, handle, identifier)) {
+					return -1;
+				}
 				blen = (sig[pos + 1] << 24) | (sig[pos + 2] << 16) | (sig[pos + 3] << 8) | sig[pos + 4];
 				pos = pos + 5;
 				break;
@@ -1059,7 +1081,16 @@ int SYMEXPORT alpm_extract_keyid(alpm_handle_t *handle, const char *identifier,
 
 		pos = pos + 4;
 
+		/* pos got changed above, so an explicit check is necessary
+		 * check for 2 as that catches another some lines down */
+		if(length_check(len, pos, 2, handle, identifier)) {
+			return -1;
+		}
 		hlen = (sig[pos] << 8) | sig[pos + 1];
+
+		if(length_check(len, pos, hlen + 2, handle, identifier)) {
+			return -1;
+		}
 		pos = pos + hlen + 2;
 
 		ulen = (sig[pos] << 8) | sig[pos + 1];
@@ -1072,30 +1103,39 @@ int SYMEXPORT alpm_extract_keyid(alpm_handle_t *handle, const char *identifier,
 				slen = sig[spos];
 				spos = spos + 1;
 			} else if(sig[spos] < 255) {
+				if(length_check(pos + ulen, spos, 2, handle, identifier)){
+					return -1;
+				}
 				slen = (sig[spos] << 8) | sig[spos + 1];
 				spos = spos + 2;
 			} else {
+				/* check for pos and spos, as spos is still pos */
+				if(length_check(len, pos, 5, handle, identifier)) {
+					return -1;
+				}
 				slen = (sig[spos + 1] << 24) | (sig[spos + 2] << 16) | (sig[spos + 3] << 8) | sig[spos + 4];
 				spos = spos + 5;
 			}
-
 			if(sig[spos] == 16) {
 				/* issuer key ID */
 				char key[17];
 				size_t i;
+				if(length_check(pos + ulen, spos, 8, handle, identifier)) {
+					return -1;
+				}
 				for (i = 0; i < 8; i++) {
 					sprintf(&key[i * 2], "%02X", sig[spos + i + 1]);
 				}
 				*keys = alpm_list_add(*keys, strdup(key));
 				break;
 			}
-
+			if(length_check(pos + ulen + 1, spos, slen, handle, identifier)) {
+				return -1;
+			}
 			spos = spos + slen;
 		}
-
 		pos = pos + (blen - hlen - 8);
 	}
-
 	return 0;
 }
 
-- 
2.14.2