Skip to content

Resolved packet size#6214

Merged
poettering merged 4 commits into
systemd:masterfrom
keszybz:resolved-packet-size
Jun 28, 2017
Merged

Resolved packet size#6214
poettering merged 4 commits into
systemd:masterfrom
keszybz:resolved-packet-size

Conversation

@keszybz

@keszybz keszybz commented Jun 27, 2017

Copy link
Copy Markdown
Member

No description provided.

keszybz added 2 commits June 27, 2017 13:19
The allocation size was calculated in a complicated way, and for values
close to the page size we would actually allocate less than requested.

Reported by Chris Coulson <chris.coulson@canonical.com>.

CVE-2017-9445

@poettering poettering left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great otherwise

Comment thread src/resolve/resolved-dns-packet.c Outdated

if (a < DNS_PACKET_HEADER_SIZE)
a = DNS_PACKET_HEADER_SIZE;
a = MAX(mtu, DNS_PACKET_HEADER_SIZE);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, dns_packet_new() is sometimes called with mtu == 0, and in that case we should allocate more than the absolute minimum (which is the dns packet header size), otherwise we have to resize immediately again after appending the first data to the packet.

maybe something like this:

if (mtu < UDP_PACKET_HEADER_SIZE)
        mtu = DNS_PACKET_SIZE_START;

a = MAX(mtu, DNS_PACKET_HEADER_SIZE);

or so? that way if mtu is passed as 0, we will allocate DNS_PACKET_SIZE_START bytes, which is a good starting point.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, too bad you didn't say this immediately when I sent out the patch first time ;(

I'll push a follow-up patch (separate, to help avoid confusion).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, indeed. But it took me quite a while to actually grok what the old code was supposed to do... I stared for 20min straight on your patch trying to figure out wtf the purpose of the old code was and then I got it... Sorry for not spending those 20min back then!

(might be indication to add a comment, so that the next time it's not that hard to grok again)

@keszybz

keszybz commented Jun 27, 2017

Copy link
Copy Markdown
Member Author

Updated, PTAL.

@poettering

Copy link
Copy Markdown
Member

excellent! thanks a ton for fixing this!

@poettering poettering added the good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed label Jun 27, 2017
assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, i) == 0);

log_debug("dns_packet_new: %zu → %zu", i, p->allocated);
assert_se(p->allocated >= MIN(DNS_PACKET_SIZE_MAX, i));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a warning:

src/resolve/test-resolved-packet.c: In function ‘test_dns_packet_new’:
  CC       src/resolve/test_resolved_packet-resolved-dns-question.o
./src/basic/macro.h:187:30: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
                 UNIQ_T(A,aq) < UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \
                              ^
./src/basic/macro.h:44:44: note: in definition of macro ‘_unlikely_’
 #define _unlikely_(x) (__builtin_expect(!!(x),0))
                                            ^
./src/basic/macro.h:235:25: note: in expansion of macro ‘assert_message_se’
 #define assert_se(expr) assert_message_se(expr, #expr)
                         ^
src/resolve/test-resolved-packet.c:32:17: note: in expansion of macro ‘assert_se’
                 assert_se(p->allocated >= MIN(DNS_PACKET_SIZE_MAX, i));
                 ^
./src/basic/macro.h:182:19: note: in expansion of macro ‘__MIN’
 #define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
                   ^
src/resolve/test-resolved-packet.c:32:43: note: in expansion of macro ‘MIN’
                 assert_se(p->allocated >= MIN(DNS_PACKET_SIZE_MAX, i));
                                           ^
./src/basic/macro.h:187:60: warning: signed and unsigned type in conditional expression [-Wsign-compare]
                 UNIQ_T(A,aq) < UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \
                                                            ^
./src/basic/macro.h:44:44: note: in definition of macro ‘_unlikely_’
 #define _unlikely_(x) (__builtin_expect(!!(x),0))
                                            ^
./src/basic/macro.h:235:25: note: in expansion of macro ‘assert_message_se’
 #define assert_se(expr) assert_message_se(expr, #expr)
                         ^
src/resolve/test-resolved-packet.c:32:17: note: in expansion of macro ‘assert_se’
                 assert_se(p->allocated >= MIN(DNS_PACKET_SIZE_MAX, i));
                 ^
./src/basic/macro.h:182:19: note: in expansion of macro ‘__MIN’
 #define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
                   ^
src/resolve/test-resolved-packet.c:32:43: note: in expansion of macro ‘MIN’
                 assert_se(p->allocated >= MIN(DNS_PACKET_SIZE_MAX, i));
                                           ^

On the other hand, I understand what is being fixed here, so the warning can be fixed later. Thank you.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What gcc version are you using? I don't get this warning here.

@evverx evverx Jun 27, 2017

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I first noticed that warning there https://ci.centos.org/job/systemd-pr-build/3366/consoleFull. I also saw it while using

$ gcc --version
gcc (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1)

and

$ gcc --version
gcc (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using gcc 7.1. That might explain the difference.

keszybz added 2 commits June 27, 2017 17:01
dns_packet_new() is sometimes called with mtu == 0, and in that case we should
allocate more than the absolute minimum (which is the dns packet header size),
otherwise we have to resize immediately again after appending the first data to
the packet.

This partially reverts the previous commit.
This seems like the right thing to do, and apparently at least some compilers
warn about signed/unsigned comparisons with DNS_PACKET_SIZE_MAX.
@keszybz keszybz force-pushed the resolved-packet-size branch from 9d279d9 to 64a21fd Compare June 27, 2017 21:02
@keszybz

keszybz commented Jun 27, 2017

Copy link
Copy Markdown
Member Author

Updated with all requested changes.

@poettering poettering merged commit 980cb55 into systemd:master Jun 28, 2017
@keszybz keszybz deleted the resolved-packet-size branch June 28, 2017 11:46
* absolute minimum (which is the dns packet header size), to avoid
* resizing immediately again after appending the first data to the packet.
*/
if (mtu < UDP_PACKET_HEADER_SIZE)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@keszybz @poettering I was trying to understand what dns_packet_new() is really doing, and I think it may have still an error.
Why the size_t argument is named mtu ? This is not the source of the confusion ?
The only call to dns_packet_new() with a non null size is in manager_recv() of resolved-manager.c

It looks like the size pass is just the size of the data, without the UDP header, so why UDP_PACKET_HEADER_SIZE is used in the current computation ?

@benjarobin benjarobin Jun 28, 2017

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing these changes, we just should have partially revert keszybz@a016660 and also rename the parameter named mtu of dns_packet_new() to something else: dataSize ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benjarobin the reason it's called MTU is that when reading a DNS UDP packet off the network, and know the MTU of the iface, then we know how large the packet can grow to at max, and then use that to size the allocation from the beginning, so that we don't have to reallocate later on.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@poettering I see, it make sense, but the interface is never used like that.
It always set to 0 or the size of the data. That why the bug was introduced in a016660 .
The mtu include the UDP header, but here we are allocating just the size for the data, not the size of the raw packet

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@poettering If argument mtu pass to the dns_packet_new() is equal to 50 then the data that need to be allocated is only 22, since the UDP header size is equal to 28 (if I am not wrong, this is not really important, this is just for the example)

So when the parameter mtu is passed to dns_packet_new() with value 50, what is the expected allocated size ?

benjarobin referenced this pull request Jun 28, 2017
mtu is always greater than UDP_PACKET_HEADER_SIZE at this point.
Pointed out by Benjamin Robin.
eumpf0 pushed a commit to eumpf0/systemd that referenced this pull request Dec 31, 2023
* apply: "Resolved packet size" (systemd#6214) (FS#54619, CVE-2017-9445)
* fix directory group for polkit (FS#54604)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed resolve

Development

Successfully merging this pull request may close these issues.

4 participants