Bug 110249 - [kernel] [regression] [patch] setsockopt() error regression in FreeBSD 6.x
Summary: [kernel] [regression] [patch] setsockopt() error regression in FreeBSD 6.x
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 6.2-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs mailing list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-03-13 06:20 UTC by Eric P. Scott
Modified: 2017-12-31 22:32 UTC (History)
0 users

See Also:


Attachments
file.diff (238 bytes, patch)
2007-03-13 06:20 UTC, Eric P. Scott
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Eric P. Scott 2007-03-13 06:20:01 UTC
This started out as "why is net/linux-nx-client broken for
FreeBSD 6.x," but turns out to have far deeper implications.

It should come as no surprise there's a lot of code out there
that invokes system calls that might fail, and makes certain
assumptions about how such failures will be reported.

Sources intended to be cross-platform sometimes need to make
allowances for differing implementations; e.g. some "System V-
derived" environments may not behave identically to "BSD-derived"
ones.  However, once the characteristics of a particular platform
are established, they're expected to remain essentially
immutable.  On those rare occasions where it's deemed necessary
to modify an ABI, extreme care must be taken to do so as non-
destructively as possible.  Mitigation strategies may take many
forms, such as creating additional sysent[] vectors, or providing
compatibility knobs.

This PR is about what happens when an executable attempts to set
TCP_NODELAY on a UNIX protocol socket.  This is, of course, a
"stupid" thing for an program to attempt.  It can't possibly
succeed, and software developers Should Know Better.  However, it
happens in The Real World, and we need to respect that.

On FreeBSD 4.x/5.x and Linux 2.4.x/2.6.x, the specific error
reported in this case is [EOPNOTSUPP].  Mac OS X 10.4.x and
DragonFly are also in this camp.

OpenBSD, Solaris 8/9, and Mac OS X 10.3.x return [ENOPROTOOPT]
instead.

The descriptions of both error codes in the intro(2) manual
page would tend to suggest either one is plausible in this
situation, and Real World code that's intended to be "reasonably
portable" typically treats either one identically.

The lone dissenter had been NetBSD, which, beginning with their
1.4 release, picked [EINVAL].  In The Early Days of UNIX (when
there just weren't that many error codes defined), that might
have been a logical choice.  I claim it's not a wise one today.

Shortly before FreeBSD 6.0 was released, some well-meaning,
but reckless, soul made the terrible mistake of inflicting
NetBSD's braindamage upon uipc_ctloutput(), and this appears to
be the result of src/kern/uipc_usrreq.c CVS Revision 1.153:

"Check sopt_level in uipc_ctloutput() and return early if it is non-zero.
This prevents unintended consequnces[sic] when an application calls things like
setsockopt(x, SOL_SOCKET, SO_REUSEADDR, ...) on a Unix domain socket."

I understand why it was put in there, and what it was intended to
accomplish, but it's too heavy-handed--especially considering its
adverse impact on anything using compat4x, compat5x, or the
Linuxulator.  It's also inconsistent with what's documented on
the setsockopt(2) and unix(4) man pages for 6.2-RELEASE.  The
documentation is fine; it's the kernel that needs to conform.

I'm proposing simply modifying the return value to be [EOPNOTSUPP].
I've tested this change using a patched kernel, and it unbroke all
of the legacy FreeBSD executables and Linux binaries I tried.

Fix: [This is for 6.2-RELEASE; -CURRENT is similar, except there's no UNP_LOCK()]
How-To-Repeat: #include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>

main(int argc, char *argv[])
{
	register int s;
	int v;

	if ((s=socket(PF_UNIX, SOCK_STREAM, 0))<0) {
		perror("socket");
		exit(1);
	}
	v=1;
	if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const void *)&v,
		(socklen_t)sizeof v)<0) {
		perror("TCP_NODELAY");
		(void)fflush(stderr);
	}
	(void)close(s);
	exit(0);
}
Comment 1 K. Macy freebsd_committer 2007-11-16 21:25:59 UTC
Responsible Changed
From-To: freebsd-bugs->kmacy


Interoperability should always be worked towards where it is easy to maintain.
Comment 2 Gavin Atkinson freebsd_committer freebsd_triage 2011-05-29 23:05:54 UTC
Responsible Changed
From-To: kmacy->freebsd-net

kmacy has asked for all of his PRs to be reassigned back to the pool.
Comment 3 Eitan Adler freebsd_committer freebsd_triage 2017-12-31 08:01:42 UTC
For bugs matching the following criteria:

Status: In Progress Changed: (is less than) 2014-06-01

Reset to default assignee and clear in-progress tags.

Mail being skipped