Bugzilla will be upgraded to version 5.0. The upgrade date is tentatively scheduled for 2 December 2018, pending final testing and feedback.
Bug 1498210 - domain lookup by TXT record can crash idmapd if the answer is more than 127 characters
domain lookup by TXT record can crash idmapd if the answer is more than 127 c...
Status: CLOSED ERRATA
Product: Red Hat Enterprise Linux 7
Classification: Red Hat
Component: libnfsidmap (Show other bugs)
7.4
Unspecified Unspecified
unspecified Severity unspecified
: rc
: ---
Assigned To: Steve Dickson
Yongcheng Yang
: EasyFix, Reopened, Reproducer
Depends On:
Blocks: 1420851 1469559
  Show dependency treegraph
 
Reported: 2017-10-03 14:17 EDT by Frank Sorenson
Modified: 2018-04-10 14:51 EDT (History)
7 users (show)

See Also:
Fixed In Version: libnfsidmap-0.25-18.el7
Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2018-04-10 14:51:32 EDT
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)
proposed patch (1.11 KB, message/rfc822)
2017-10-03 14:17 EDT, Frank Sorenson
no flags Details


External Trackers
Tracker ID Priority Status Summary Last Updated
Red Hat Product Errata RHBA-2018:1016 None None None 2018-04-10 14:51 EDT

  None (edit)
Description Frank Sorenson 2017-10-03 14:17:51 EDT
Created attachment 1333870 [details]
proposed patch

Description of problem:

If the 'Domain' is not specified in /etc/idmapd.conf, libnfsidmap will query dns for a TXT record '_nfsv4idmapdomain' in the system's dns domain.  If the answer from dns is longer than 127 characters, idmapd will interpret the answer length incorrectly, leading to a segfault and crash


Version-Release number of selected component (if applicable):

libnfsidmap beginning with version 0.25-16


How reproducible:

see below

Steps to Reproduce:

create a long TXT record (> 127 characters) for _nfsv4idmapdomain in the system's dns domain.  For server.example.com, the following should work in dndmasq:

txt-record=_nfsv4idmapdomain.example.com,"v=spf1 mx ip4:10.0.0.1 include:spf1.subdomain.example.com include:spf2.subdomain.example.com include:spf3.subdomain.example.com ~all"

# echo -n "v=spf1 mx ip4:10.0.0.1 include:spf1.subdomain.example.com include:spf2.subdomain.example.com include:spf3.subdomain.example.com ~all" | wc -c
132

remove any 'Domain = ...' configuration from /etc/idmapd.conf

# sed -i s/^Domain/#Domain/g /etc/idmapd.conf

start idmapd

# /usr/sbin/rpc.idmapd -v -f


Actual results:

idmapd crashes


Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51	}

(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007ffff75ec4a0 in __GI_abort () at abort.c:89
#2  0x00007ffff76308e1 in __libc_message (do_abort=do_abort@entry=2, fmt=fmt@entry=0x7ffff774b70a "*** %s ***: %s terminated\n")
    at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff76d7aa7 in __GI___fortify_fail (msg=msg@entry=0x7ffff774b6a1 "buffer overflow detected") at fortify_fail.c:30
#4  0x00007ffff76d5820 in __GI___chk_fail () at chk_fail.c:28
#5  0x00007ffff798759a in memcpy (__len=18446744073709551490, __src=<optimized out>, __dest=0x555555771c40)
    at /usr/include/bits/string3.h:53
#6  dns_txt_query (nfs4domain=0x7ffff7b8c050 <default_domain>, domain=<optimized out>) at libnfsidmap.c:202
#7  domain_from_dns (domain=0x7ffff7b8c050 <default_domain>) at libnfsidmap.c:230
#8  0x00007ffff7987cf5 in nfs4_init_name_mapping (conffile=<optimized out>) at libnfsidmap.c:355
#9  0x00005555555561b6 in main (argc=3, argv=0x7fffffffdfc8) at idmapd.c:328

(gdb) frame 5
#5  0x00007ffff798759a in memcpy (__len=18446744073709551490, __src=<optimized out>, __dest=0x555555771c40)
    at /usr/include/bits/string3.h:53
53	  return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));

(gdb) p __len
$3 = 18446744073709551490

(gdb) frame 6
#6  dns_txt_query (nfs4domain=0x7ffff7b8c050 <default_domain>, domain=<optimized out>) at libnfsidmap.c:202
202		memcpy(answ, mptr, len);

(gdb) p len
$4 = -126

(gdb) p (int)18446744073709551490
$11 = -126


Expected results:

no crash


Additional info:


A TXT record answer longer than 255 characters will be split at 255, and the multiple parts will be present:

bytes  
2      data length (total bytes)
1      txt length
0-255  txt data
...
1      txt length
0-255  txt data
1      txt length
0-255  txt data
...
(as needed)

casting to an 'unsigned char' before casting to 'int' should allow reading as many as 255 characters
Comment 7 Justin Mitchell 2017-11-15 08:07:30 EST
Has already been fixed by bug 1455923 which included me fixing a bunch of signedness issues
Comment 8 Steve Dickson 2017-11-15 09:31:17 EST

*** This bug has been marked as a duplicate of bug 1455923 ***
Comment 9 Steve Dickson 2017-11-15 09:35:05 EST
(In reply to Justin Mitchell from comment #7)
> Has already been fixed by bug 1455923 which included me fixing a bunch of
> signedness issues

Re-thinking... is there a single patch that just addresses this issue?
Comment 10 Justin Mitchell 2017-11-15 09:54:14 EST
The closest committed patch would be 545b7409 in the nfs-utils tree, but thats after libnfsidmap was merged in.

On its own the relevant chunk that could be applied to the libnfsidmap tree would be:

diff --git a/libnfsidmap.c b/libnfsidmap.c
--- a/libnfsidmap.c
+++ b/libnfsidmap.c
@@ -128,7 +128,8 @@ static int id_as_chars(char *name, uid_t *id)
 static int dns_txt_query(char *domain, char **nfs4domain)
 {
        char *txtname = NFS4DNSTXTREC;
-       char *msg, *answ, *eom, *mptr; 
+       unsigned char *msg, *eom, *mptr;
+       char *answ;
        int len, status = -1;
        HEADER *hdr;
Comment 11 Steve Dickson 2017-11-15 10:31:42 EST
(In reply to Justin Mitchell from comment #10)
> The closest committed patch would be 545b7409 in the nfs-utils tree, but
> thats after libnfsidmap was merged in.
> 
> On its own the relevant chunk that could be applied to the libnfsidmap tree
> would be:
> 
> diff --git a/libnfsidmap.c b/libnfsidmap.c
> --- a/libnfsidmap.c
> +++ b/libnfsidmap.c
> @@ -128,7 +128,8 @@ static int id_as_chars(char *name, uid_t *id)
>  static int dns_txt_query(char *domain, char **nfs4domain)
>  {
>         char *txtname = NFS4DNSTXTREC;
> -       char *msg, *answ, *eom, *mptr; 
> +       unsigned char *msg, *eom, *mptr;
> +       char *answ;
>         int len, status = -1;
>         HEADER *hdr;

This seems simple enough with little risk... 

Devel Ack
Comment 12 Frank Sorenson 2017-11-15 10:39:12 EST
Yes, I believe this would also work, since the length would then be cast from (unsigned char) to (int), and the length should stay a positive number:

...
       unsigned char *msg, *eom, *mptr;
       int len, status = -1;
...
       /* get the lenght field */
       len = (int)*mptr++;
       /* copy the data */
       memcpy(answ, mptr, len);
       answ[len] = '\0';

as far as I can tell, it should be safe for 'answ' to remain signed, though I haven't looked closely.
Comment 13 Justin Mitchell 2017-11-15 11:09:04 EST
I had already made these changes when merging libnfsidmap info nfs-utils as i was trying to clear the many warnings the old code produced, then wondered why i couldn't reproduce this bug when using that code base.

How likely or important is it to support hostnames longer then 255 chars ? as if needed i can work a proper fix into a future patch.
Comment 14 Steve Dickson 2017-11-15 11:15:14 EST
(In reply to Steve Dickson from comment #11)
> (In reply to Justin Mitchell from comment #10)
> > The closest committed patch would be 545b7409 in the nfs-utils tree, but
> > thats after libnfsidmap was merged in.
> > 
> > On its own the relevant chunk that could be applied to the libnfsidmap tree
> > would be:
> > 
> > diff --git a/libnfsidmap.c b/libnfsidmap.c
> > --- a/libnfsidmap.c
> > +++ b/libnfsidmap.c
> > @@ -128,7 +128,8 @@ static int id_as_chars(char *name, uid_t *id)
> >  static int dns_txt_query(char *domain, char **nfs4domain)
> >  {
> >         char *txtname = NFS4DNSTXTREC;
> > -       char *msg, *answ, *eom, *mptr; 
> > +       unsigned char *msg, *eom, *mptr;
> > +       char *answ;
> >         int len, status = -1;
> >         HEADER *hdr;
> 
> This seems simple enough with little risk... 
> 
> Devel Ack

Is there a similar patch we can do for bug 1455923?
Comment 15 Justin Mitchell 2017-11-15 13:13:28 EST
1455923 is not so easy, there i completely rewrote the line parser as it was just terrible code that overran its buffer, so its difficult to fix just the one issue. I will work up a patch with a more minimal rewite of the parser for use if we cant manage to rebase to the newer tree.
Comment 18 Yongcheng Yang 2017-11-19 22:20:02 EST
This problem has been fixed in libnfsidmap-0.25-18.el7

Moving to VERIFIED according to Comment #17.
Comment 21 errata-xmlrpc 2018-04-10 14:51:32 EDT
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2018:1016

Note You need to log in before you can comment on or make changes to this bug.