Note: This bug is displayed in read-only format because
the product is no longer active in Red Hat Bugzilla.
RHEL Engineering is moving the tracking of its product development work on RHEL 6 through RHEL 9 to Red Hat Jira (issues.redhat.com). If you're a Red Hat customer, please continue to file support cases via the Red Hat customer portal. If you're not, please head to the "RHEL project" in Red Hat Jira and file new tickets here. Individual Bugzilla bugs in the statuses "NEW", "ASSIGNED", and "POST" are being migrated throughout September 2023. Bugs of Red Hat partners with an assigned Engineering Partner Manager (EPM) are migrated in late September as per pre-agreed dates. Bugs against components "kernel", "kernel-rt", and "kpatch" are only migrated if still in "NEW" or "ASSIGNED". If you cannot log in to RH Jira, please consult article #7032570. That failing, please send an e-mail to the RH Jira admins at rh-issues@redhat.com to troubleshoot your issue as a user management inquiry. The email creates a ServiceNow ticket with Red Hat. Individual Bugzilla bugs that are migrated will be moved to status "CLOSED", resolution "MIGRATED", and set with "MigratedToJIRA" in "Keywords". The link to the successor Jira issue will be found under "Links", have a little "two-footprint" icon next to it, and direct you to the "RHEL project" in Red Hat Jira (issue links are of type "https://issues.redhat.com/browse/RHEL-XXXX", where "X" is a digit). This same link will be available in a blue banner at the top of the page informing you that that bug has been migrated.
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
(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?
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;
(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
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.
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.
(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?
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.
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
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