* [Qemu-devel] [PATCH] Fix scrambling of >32KB packets in slirp
@ 2006-05-01 2:55 Ed Swierk
2006-05-01 11:08 ` Fabrice Bellard
0 siblings, 1 reply; 5+ messages in thread
From: Ed Swierk @ 2006-05-01 2:55 UTC (permalink / raw
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 531 bytes --]
In several places in qemu's slirp code, signed and unsigned ints are
used interchangeably when dealing with IP packet lengths and offsets.
This causes IP packets greater than 32K in length to be scrambled in
various interesting ways that are extremely difficult to troubleshoot.
Although large IP packets are fairly rare in practice, certain
UDP-based protocols like NFS use them extensively.
The attached patch wraps IP packet lengths and offsets in macros that
ensure they are always properly treated as unsigned values.
--Ed
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: qemu-slirp-32k-packets.patch --]
[-- Type: text/x-patch; name="qemu-slirp-32k-packets.patch", Size: 4430 bytes --]
diff -burN qemu-snapshot-2006-03-27_23.orig/slirp/ip.h qemu-snapshot-2006-03-27_23/slirp/ip.h
--- qemu-snapshot-2006-03-27_23.orig/slirp/ip.h 2004-04-21 17:10:47.000000000 -0700
+++ qemu-snapshot-2006-03-27_23/slirp/ip.h 2006-04-06 00:28:49.000000000 -0700
@@ -79,6 +79,11 @@
* We declare ip_len and ip_off to be short, rather than u_short
* pragmatically since otherwise unsigned comparisons can result
* against negative integers quite easily, and fail in subtle ways.
+ *
+ * The only problem with the above theory is that these quantities
+ * are in fact unsigned, and sorting fragments by a signed version
+ * of ip_off doesn't work very well, nor does length checks on
+ * ip packets with a signed version of their length!
*/
struct ip {
#ifdef WORDS_BIGENDIAN
@@ -101,6 +106,9 @@
struct in_addr ip_src,ip_dst; /* source and dest address */
};
+#define IP_OFF(ip) (*(u_int16_t *)&((ip)->ip_off))
+#define IP_LEN(ip) (*(u_int16_t *)&((ip)->ip_len))
+
#define IP_MAXPACKET 65535 /* maximum packet size */
/*
diff -burN qemu-snapshot-2006-03-27_23.orig/slirp/ip_input.c qemu-snapshot-2006-03-27_23/slirp/ip_input.c
--- qemu-snapshot-2006-03-27_23.orig/slirp/ip_input.c 2004-04-21 17:10:47.000000000 -0700
+++ qemu-snapshot-2006-03-27_23/slirp/ip_input.c 2006-04-06 00:32:19.000000000 -0700
@@ -111,7 +111,7 @@
* Convert fields to host representation.
*/
NTOHS(ip->ip_len);
- if (ip->ip_len < hlen) {
+ if (IP_LEN(ip) < hlen) {
ipstat.ips_badlen++;
goto bad;
}
@@ -124,13 +124,13 @@
* Trim mbufs if longer than we expect.
* Drop packet if shorter than we expect.
*/
- if (m->m_len < ip->ip_len) {
+ if (m->m_len < IP_LEN(ip)) {
ipstat.ips_tooshort++;
goto bad;
}
/* Should drop packet if mbuf too long? hmmm... */
- if (m->m_len > ip->ip_len)
- m_adj(m, ip->ip_len - m->m_len);
+ if (m->m_len > IP_LEN(ip))
+ m_adj(m, IP_LEN(ip) - m->m_len);
/* check ip_ttl for a correct ICMP reply */
if(ip->ip_ttl==0 || ip->ip_ttl==1) {
@@ -191,7 +191,7 @@
* or if this is not the first fragment,
* attempt reassembly; if it succeeds, proceed.
*/
- if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
+ if (((struct ipasfrag *)ip)->ipf_mff & 1 || IP_OFF(ip)) {
ipstat.ips_fragments++;
ip = ip_reass((struct ipasfrag *)ip, fp);
if (ip == 0)
@@ -281,7 +281,7 @@
*/
for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp;
q = (struct ipasfrag *)q->ipf_next)
- if (q->ip_off > ip->ip_off)
+ if (IP_OFF(q) > IP_OFF(ip))
break;
/*
@@ -290,10 +290,10 @@
* segment. If it provides all of our data, drop us.
*/
if (q->ipf_prev != (ipasfragp_32)fp) {
- i = ((struct ipasfrag *)(q->ipf_prev))->ip_off +
- ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off;
+ i = IP_OFF((struct ipasfrag *)(q->ipf_prev)) +
+ IP_LEN((struct ipasfrag *)(q->ipf_prev)) - IP_OFF(ip);
if (i > 0) {
- if (i >= ip->ip_len)
+ if (i >= IP_LEN(ip))
goto dropfrag;
m_adj(dtom(ip), i);
ip->ip_off += i;
@@ -305,9 +305,9 @@
* While we overlap succeeding segments trim them or,
* if they are completely covered, dequeue them.
*/
- while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
- i = (ip->ip_off + ip->ip_len) - q->ip_off;
- if (i < q->ip_len) {
+ while (q != (struct ipasfrag *)fp && IP_OFF(ip) + IP_LEN(ip) > IP_OFF(q)) {
+ i = (IP_OFF(ip) + IP_LEN(ip)) - IP_OFF(q);
+ if (i < IP_LEN(q)) {
q->ip_len -= i;
q->ip_off += i;
m_adj(dtom(q), i);
@@ -327,9 +327,9 @@
next = 0;
for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp;
q = (struct ipasfrag *) q->ipf_next) {
- if (q->ip_off != next)
+ if (IP_OFF(q) != next)
return (0);
- next += q->ip_len;
+ next += IP_LEN(q);
}
if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1)
return (0);
diff -burN qemu-snapshot-2006-03-27_23.orig/slirp/udp.c qemu-snapshot-2006-03-27_23/slirp/udp.c
--- qemu-snapshot-2006-03-27_23.orig/slirp/udp.c 2006-04-06 00:24:30.000000000 -0700
+++ qemu-snapshot-2006-03-27_23/slirp/udp.c 2006-04-06 00:32:55.000000000 -0700
@@ -111,12 +111,12 @@
*/
len = ntohs((u_int16_t)uh->uh_ulen);
- if (ip->ip_len != len) {
- if (len > ip->ip_len) {
+ if (IP_LEN(ip) != len) {
+ if (len > IP_LEN(ip)) {
udpstat.udps_badlen++;
goto bad;
}
- m_adj(m, len - ip->ip_len);
+ m_adj(m, len - IP_LEN(ip));
ip->ip_len = len;
}
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] Fix scrambling of >32KB packets in slirp
2006-05-01 2:55 [Qemu-devel] [PATCH] Fix scrambling of >32KB packets in slirp Ed Swierk
@ 2006-05-01 11:08 ` Fabrice Bellard
2006-05-01 16:19 ` Kenneth Duda
2006-05-02 2:11 ` Ed Swierk
0 siblings, 2 replies; 5+ messages in thread
From: Fabrice Bellard @ 2006-05-01 11:08 UTC (permalink / raw
To: qemu-devel
Ed Swierk wrote:
> In several places in qemu's slirp code, signed and unsigned ints are
> used interchangeably when dealing with IP packet lengths and offsets.
> This causes IP packets greater than 32K in length to be scrambled in
> various interesting ways that are extremely difficult to troubleshoot.
>
> Although large IP packets are fairly rare in practice, certain
> UDP-based protocols like NFS use them extensively.
>
> The attached patch wraps IP packet lengths and offsets in macros that
> ensure they are always properly treated as unsigned values.
Why not changing the definition itself to uint16_t and verifying each
occurence of ip_off and ip_len ?
Fabrice.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] Fix scrambling of >32KB packets in slirp
2006-05-01 11:08 ` Fabrice Bellard
@ 2006-05-01 16:19 ` Kenneth Duda
2006-05-01 18:05 ` Fabrice Bellard
2006-05-02 2:11 ` Ed Swierk
1 sibling, 1 reply; 5+ messages in thread
From: Kenneth Duda @ 2006-05-01 16:19 UTC (permalink / raw
To: qemu-devel
Well that is a good question. When I made this patch, I wanted to
respect the comment in the code that the author felt that using a
signed data type was safer in some cases. However, I will admit that
I do not understand this reasoning, and I agree that switching to an
unsigned data type would be better. Would you like us to resubmit
this patch in that form?
-Ken
On 5/1/06, Fabrice Bellard <fabrice@bellard.org> wrote:
> Ed Swierk wrote:
> > In several places in qemu's slirp code, signed and unsigned ints are
> > used interchangeably when dealing with IP packet lengths and offsets.
> > This causes IP packets greater than 32K in length to be scrambled in
> > various interesting ways that are extremely difficult to troubleshoot.
> >
> > Although large IP packets are fairly rare in practice, certain
> > UDP-based protocols like NFS use them extensively.
> >
> > The attached patch wraps IP packet lengths and offsets in macros that
> > ensure they are always properly treated as unsigned values.
>
> Why not changing the definition itself to uint16_t and verifying each
> occurence of ip_off and ip_len ?
>
> Fabrice.
>
>
> _______________________________________________
> Qemu-devel mailing list
> Qemu-devel@nongnu.org
> http://lists.nongnu.org/mailman/listinfo/qemu-devel
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] Fix scrambling of >32KB packets in slirp
2006-05-01 16:19 ` Kenneth Duda
@ 2006-05-01 18:05 ` Fabrice Bellard
0 siblings, 0 replies; 5+ messages in thread
From: Fabrice Bellard @ 2006-05-01 18:05 UTC (permalink / raw
To: qemu-devel
Yes, I would prefer that you resubmit a patch using unsigned types.
Fabrice.
Kenneth Duda wrote:
> Well that is a good question. When I made this patch, I wanted to
> respect the comment in the code that the author felt that using a
> signed data type was safer in some cases. However, I will admit that
> I do not understand this reasoning, and I agree that switching to an
> unsigned data type would be better. Would you like us to resubmit
> this patch in that form?
>
> -Ken
>
> On 5/1/06, Fabrice Bellard <fabrice@bellard.org> wrote:
>
>> Ed Swierk wrote:
>> > In several places in qemu's slirp code, signed and unsigned ints are
>> > used interchangeably when dealing with IP packet lengths and offsets.
>> > This causes IP packets greater than 32K in length to be scrambled in
>> > various interesting ways that are extremely difficult to troubleshoot.
>> >
>> > Although large IP packets are fairly rare in practice, certain
>> > UDP-based protocols like NFS use them extensively.
>> >
>> > The attached patch wraps IP packet lengths and offsets in macros that
>> > ensure they are always properly treated as unsigned values.
>>
>> Why not changing the definition itself to uint16_t and verifying each
>> occurence of ip_off and ip_len ?
>>
>> Fabrice.
>>
>>
>> _______________________________________________
>> Qemu-devel mailing list
>> Qemu-devel@nongnu.org
>> http://lists.nongnu.org/mailman/listinfo/qemu-devel
>>
>
>
> _______________________________________________
> Qemu-devel mailing list
> Qemu-devel@nongnu.org
> http://lists.nongnu.org/mailman/listinfo/qemu-devel
>
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] Fix scrambling of >32KB packets in slirp
2006-05-01 11:08 ` Fabrice Bellard
2006-05-01 16:19 ` Kenneth Duda
@ 2006-05-02 2:11 ` Ed Swierk
1 sibling, 0 replies; 5+ messages in thread
From: Ed Swierk @ 2006-05-02 2:11 UTC (permalink / raw
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 769 bytes --]
On 5/1/06, Fabrice Bellard <fabrice@bellard.org> wrote:
> Why not changing the definition itself to uint16_t and verifying each
> occurence of ip_off and ip_len ?
Indeed, why not. This is the solution adopted by Apple's OpenDarwin
(another BSD derivative). The attached patch changes the signed
definitions to unsigned.
I tried to verify by inspecting each occurrence of ip_off and ip_len;
in cases where the values are implicitly converted, the unsigned short
is converted to a signed int, which should be OK assuming 32-bit ints.
Does qemu support any platforms with 16-bit ints?
I also ran some tests (on i386 Linux) to ensure that slirp still works
as expected, and also handles packets > 32KB. Of course, more testing
on other platforms would be welcome.
--Ed
[-- Attachment #2: qemu-slirp-unsigned.patch --]
[-- Type: text/x-patch, Size: 1646 bytes --]
diff -BurN qemu.orig/slirp/ip.h qemu/slirp/ip.h
--- qemu.orig/slirp/ip.h 2004-04-22 00:10:47.000000000 +0000
+++ qemu/slirp/ip.h 2006-05-02 02:07:34.000000000 +0000
@@ -75,10 +75,6 @@
/*
* Structure of an internet header, naked of options.
- *
- * We declare ip_len and ip_off to be short, rather than u_short
- * pragmatically since otherwise unsigned comparisons can result
- * against negative integers quite easily, and fail in subtle ways.
*/
struct ip {
#ifdef WORDS_BIGENDIAN
@@ -89,9 +85,9 @@
ip_v:4; /* version */
#endif
u_int8_t ip_tos; /* type of service */
- int16_t ip_len; /* total length */
+ u_int16_t ip_len; /* total length */
u_int16_t ip_id; /* identification */
- int16_t ip_off; /* fragment offset field */
+ u_int16_t ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* don't fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
@@ -212,7 +208,7 @@
caddr32_t ih_next, ih_prev; /* for protocol sequence q's */
u_int8_t ih_x1; /* (unused) */
u_int8_t ih_pr; /* protocol */
- int16_t ih_len; /* protocol length */
+ u_int16_t ih_len; /* protocol length */
struct in_addr ih_src; /* source internet address */
struct in_addr ih_dst; /* destination internet address */
};
@@ -253,9 +249,9 @@
u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit
* to avoid destroying tos (PPPDTRuu);
* copied from (ip_off&IP_MF) */
- int16_t ip_len;
+ u_int16_t ip_len;
u_int16_t ip_id;
- int16_t ip_off;
+ u_int16_t ip_off;
u_int8_t ip_ttl;
u_int8_t ip_p;
u_int16_t ip_sum;
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2006-05-02 2:11 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-01 2:55 [Qemu-devel] [PATCH] Fix scrambling of >32KB packets in slirp Ed Swierk
2006-05-01 11:08 ` Fabrice Bellard
2006-05-01 16:19 ` Kenneth Duda
2006-05-01 18:05 ` Fabrice Bellard
2006-05-02 2:11 ` Ed Swierk
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.