aboutsummaryrefslogtreecommitdiffstats
path: root/net/x25
diff options
context:
space:
mode:
authorandrew hendry <andrew.hendry@gmail.com>2011-02-06 19:08:15 -0500
committerDavid S. Miller <davem@davemloft.net>2011-02-07 16:41:38 -0500
commit95c3043008ca8449feb96aba5481fe31c2ea750b (patch)
tree1a80c238a56c1dc22a8b962f98ee1af363186e64 /net/x25
parent711c914688163dbe757c174788e20695088478e5 (diff)
x25: possible skb leak on bad facilities
Originally x25_parse_facilities returned -1 for an error 0 meaning 0 length facilities >0 the length of the facilities parsed. 5ef41308f94dc ("x25: Prevent crashing when parsing bad X.25 facilities") introduced more error checking in x25_parse_facilities however used 0 to indicate bad parsing a6331d6f9a429 ("memory corruption in X.25 facilities parsing") followed this further for DTE facilities, again using 0 for bad parsing. The meaning of 0 got confused in the callers. If the facilities are messed up we can't determine where the data starts. So patch makes all parsing errors return -1 and ensures callers close and don't use the skb further. Reported-by: Andy Whitcroft <apw@canonical.com> Signed-off-by: Andrew Hendry <andrew.hendry@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/x25')
-rw-r--r--net/x25/x25_facilities.c28
-rw-r--r--net/x25/x25_in.c14
2 files changed, 30 insertions, 12 deletions
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index 55187c8f6420..406207515b5e 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -27,9 +27,19 @@
27#include <net/sock.h> 27#include <net/sock.h>
28#include <net/x25.h> 28#include <net/x25.h>
29 29
30/* 30/**
31 * Parse a set of facilities into the facilities structures. Unrecognised 31 * x25_parse_facilities - Parse facilities from skb into the facilities structs
32 * facilities are written to the debug log file. 32 *
33 * @skb: sk_buff to parse
34 * @facilities: Regular facilites, updated as facilities are found
35 * @dte_facs: ITU DTE facilities, updated as DTE facilities are found
36 * @vc_fac_mask: mask is updated with all facilities found
37 *
38 * Return codes:
39 * -1 - Parsing error, caller should drop call and clean up
40 * 0 - Parse OK, this skb has no facilities
41 * >0 - Parse OK, returns the length of the facilities header
42 *
33 */ 43 */
34int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, 44int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
35 struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask) 45 struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
@@ -62,7 +72,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
62 switch (*p & X25_FAC_CLASS_MASK) { 72 switch (*p & X25_FAC_CLASS_MASK) {
63 case X25_FAC_CLASS_A: 73 case X25_FAC_CLASS_A:
64 if (len < 2) 74 if (len < 2)
65 return 0; 75 return -1;
66 switch (*p) { 76 switch (*p) {
67 case X25_FAC_REVERSE: 77 case X25_FAC_REVERSE:
68 if((p[1] & 0x81) == 0x81) { 78 if((p[1] & 0x81) == 0x81) {
@@ -107,7 +117,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
107 break; 117 break;
108 case X25_FAC_CLASS_B: 118 case X25_FAC_CLASS_B:
109 if (len < 3) 119 if (len < 3)
110 return 0; 120 return -1;
111 switch (*p) { 121 switch (*p) {
112 case X25_FAC_PACKET_SIZE: 122 case X25_FAC_PACKET_SIZE:
113 facilities->pacsize_in = p[1]; 123 facilities->pacsize_in = p[1];
@@ -130,7 +140,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
130 break; 140 break;
131 case X25_FAC_CLASS_C: 141 case X25_FAC_CLASS_C:
132 if (len < 4) 142 if (len < 4)
133 return 0; 143 return -1;
134 printk(KERN_DEBUG "X.25: unknown facility %02X, " 144 printk(KERN_DEBUG "X.25: unknown facility %02X, "
135 "values %02X, %02X, %02X\n", 145 "values %02X, %02X, %02X\n",
136 p[0], p[1], p[2], p[3]); 146 p[0], p[1], p[2], p[3]);
@@ -139,18 +149,18 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
139 break; 149 break;
140 case X25_FAC_CLASS_D: 150 case X25_FAC_CLASS_D:
141 if (len < p[1] + 2) 151 if (len < p[1] + 2)
142 return 0; 152 return -1;
143 switch (*p) { 153 switch (*p) {
144 case X25_FAC_CALLING_AE: 154 case X25_FAC_CALLING_AE:
145 if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1) 155 if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
146 return 0; 156 return -1;
147 dte_facs->calling_len = p[2]; 157 dte_facs->calling_len = p[2];
148 memcpy(dte_facs->calling_ae, &p[3], p[1] - 1); 158 memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
149 *vc_fac_mask |= X25_MASK_CALLING_AE; 159 *vc_fac_mask |= X25_MASK_CALLING_AE;
150 break; 160 break;
151 case X25_FAC_CALLED_AE: 161 case X25_FAC_CALLED_AE:
152 if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1) 162 if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
153 return 0; 163 return -1;
154 dte_facs->called_len = p[2]; 164 dte_facs->called_len = p[2];
155 memcpy(dte_facs->called_ae, &p[3], p[1] - 1); 165 memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
156 *vc_fac_mask |= X25_MASK_CALLED_AE; 166 *vc_fac_mask |= X25_MASK_CALLED_AE;
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index f729f022be69..15de65f04719 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -91,10 +91,10 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
91{ 91{
92 struct x25_address source_addr, dest_addr; 92 struct x25_address source_addr, dest_addr;
93 int len; 93 int len;
94 struct x25_sock *x25 = x25_sk(sk);
94 95
95 switch (frametype) { 96 switch (frametype) {
96 case X25_CALL_ACCEPTED: { 97 case X25_CALL_ACCEPTED: {
97 struct x25_sock *x25 = x25_sk(sk);
98 98
99 x25_stop_timer(sk); 99 x25_stop_timer(sk);
100 x25->condition = 0x00; 100 x25->condition = 0x00;
@@ -113,14 +113,16 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
113 &dest_addr); 113 &dest_addr);
114 if (len > 0) 114 if (len > 0)
115 skb_pull(skb, len); 115 skb_pull(skb, len);
116 else if (len < 0)
117 goto out_clear;
116 118
117 len = x25_parse_facilities(skb, &x25->facilities, 119 len = x25_parse_facilities(skb, &x25->facilities,
118 &x25->dte_facilities, 120 &x25->dte_facilities,
119 &x25->vc_facil_mask); 121 &x25->vc_facil_mask);
120 if (len > 0) 122 if (len > 0)
121 skb_pull(skb, len); 123 skb_pull(skb, len);
122 else 124 else if (len < 0)
123 return -1; 125 goto out_clear;
124 /* 126 /*
125 * Copy any Call User Data. 127 * Copy any Call User Data.
126 */ 128 */
@@ -144,6 +146,12 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
144 } 146 }
145 147
146 return 0; 148 return 0;
149
150out_clear:
151 x25_write_internal(sk, X25_CLEAR_REQUEST);
152 x25->state = X25_STATE_2;
153 x25_start_t23timer(sk);
154 return 0;
147} 155}
148 156
149/* 157/*