Bug 31981

Summary: [libc] [patch] (mis)feature in getnetent parsing -- comments affect parsing results
Product: Base System Reporter: James Carlson <james.d.carlson>
Component: kernAssignee: Marcelo Araujo <araujo>
Status: Closed FIXED    
Severity: Affects Only Me CC: araujo, hrs, pfg
Priority: Normal    
Version: 4.1-RELEASE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
Updated patch none

Description James Carlson 2001-11-14 15:40:03 UTC
The problem actually goes back to ancient releases of BSD.  I looked
back to 4.2BSD, and the problem exists there.

Consider the following two entries in /etc/networks:

	test1	10
	test2	11	alias2
	test3	12	# hi there

On Solaris getnetbyname (and getnetent), we treat "test1", "test2",
and "test3" as the real network names, and "alias2" as an alias for
just network "test2."  This appears to be fairly reasonable.

On BSD, it interprets the second entry the same way we do -- network
"test2", single alias "alias2", and "test3" with no aliases.  However,
it *intentionally* treats the first case differently.  On BSD, that's
interpreted as network "test1" with alias "10".

The offending lines in /usr/src/lib/libc/net/getnetbyht.c are:

	p = strpbrk(cp, " \t");
	if (p != NULL)
		*p++ = '\0';
	net.n_net = inet_network(cp);
	net.n_addrtype = AF_INET;
	q = net.n_aliases = net_aliases;
	if (p != NULL) 
--->		cp = p;

This sets the initial pointer to the next character after the first
blank following the network number.  If there is no such character,
then this is NULL, and we just fall through with cp set to the start
of the network number.

Fix: 

Remove the "if (p != NULL)" line.
How-To-Repeat: #include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

int
main(int argc, char **argv)
{
	struct netent *np;
	unsigned char *cp;
	unsigned long ina;
	char **cpp;

	np = getnetbyname(argv[1]);
	if (np == NULL) {
		printf("getnetbyname: NULL\n");
	} else {
		cp = (unsigned char *)&np->n_net;
		printf("getnetbyname: %d %d %d %d '%s'\n", cp[0], cp[1], cp[2],
		    cp[3], np->n_name);
		if (*np->n_aliases != NULL) {
			printf("     aliases:");
			for (cpp = np->n_aliases; *cpp != NULL; cpp++)
				printf(" '%s'", *cpp);
			putchar('\n');
		}
	}
	ina = inet_network(argv[1]);
	cp = (unsigned char *)&ina;
	printf("inet_network: %d %d %d %d\n", cp[0], cp[1], cp[2],
	    cp[3]);
	return 0;
}
Comment 1 Pedro F. Giffuni freebsd_committer freebsd_triage 2015-02-19 20:15:20 UTC
This appears to have been fixed somewhat differently by r145477:

"if last line didn't have trailing space, network address was also
treated as an alias."

I am closing it but will assign it to the revision committer for reference.
Comment 2 Pedro F. Giffuni freebsd_committer freebsd_triage 2015-02-21 18:19:20 UTC
Created attachment 153285 [details]
Updated patch

Actually, this should work ... but it needs testing.
Comment 3 Marcelo Araujo freebsd_committer freebsd_triage 2015-11-17 02:29:32 UTC
I will take it.
Comment 4 Marcelo Araujo freebsd_committer freebsd_triage 2015-12-14 06:52:53 UTC
I have tested it, and I can't find where is the bug, my tests were made with/without the patch and using the software provided by the submitter, I still can't find where is the bug.

The output is always the same for me, and it looks right:
 araujo@coxinha:/tmp# ./t test1
getnetbyname: 10 0 0 0 'test1'
inet_network: 255 255 255 255
araujo@coxinha:/tmp# ./t test2
getnetbyname: 11 0 0 0 'test2'
     aliases: 'alias2'
inet_network: 255 255 255 255
araujo@coxinha:/tmp# ./t test3
getnetbyname: 12 0 0 0 'test3'
inet_network: 255 255 255 255

If no reply from you guys in the next couple weeks, I will consider this problem as solved.

Best,
Comment 5 Marcelo Araujo freebsd_committer freebsd_triage 2015-12-28 03:33:32 UTC
I can't replicate this issue.