Bug 102956

Summary: [linux] [patch] Add partial support for SO_PEERCRED in Linux emulation
Product: Base System Reporter: Marcin Cieslak <saper>
Component: kernAssignee: Dmitry Chagin <dchagin>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
file.diff none

Description Marcin Cieslak 2006-09-07 00:50:19 UTC
Current Linux getsockopt() does not support SO_PEERCRED option used to fetch UNIX domain
socket peer PID, UID and GID. 

Without this option ORACLE 10i Express Edition lsnrctl is unable to issue commands
to a running listener (including "status" and "stop").
All invocations result in the message:

TNS-01189: The listener could not authenticate the user

Linux lsnrctl using so called "OS Authentication" mode probes if UNIX socket
connection peer is the process run under to privileged "dba" group (or another group
listed in the DBA_GROUP parameter of the $ORACLE_HOME/network/admin/listener.ora file).

Security of this patch is not tested.

Known problem: Peer PID recognition is not done, we always return zero.

Fix: Modified files:
     $FreeBSD: src/sys/compat/linux/linux_socket.c,v 1.59.2.1 2006/01/10 10:12:55 glebius Exp $
     $FreeBSD: src/sys/i386/linux/linux.h,v 1.64 2005/04/13 04:31:43 mdodd Exp $
     $FreeBSD: src/sys/amd64/linux32/linux.h,v 1.1 2004/08/16 07:55:06 tjr Exp $
     $FreeBSD: src/sys/alpha/linux/linux.h,v 1.59 2004/08/16 07:05:44 tjr Exp $

How-To-Repeat: 
Perform "${ORACLE_HOME}/bin/lsnrctl status" as the Oracle user.
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2006-09-07 02:58:41 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-emulation

Over to maintainer(s).
Comment 2 Rink Springer freebsd_committer freebsd_triage 2008-03-14 08:42:14 UTC
Responsible Changed
From-To: freebsd-emulation->rink

I will deal with this - this PR has been gone unnoticed for far too long and 
we use the patch at work for a long time with no ill effects.
Comment 3 Robert Watson freebsd_committer freebsd_triage 2008-03-14 12:20:40 UTC
On Thu, 7 Sep 2006, Mark Linimon wrote:

> Synopsis: [linux] [patch] Add partial support for SO_PEERCRED in Linux emulation
>
> Responsible-Changed-From-To: freebsd-bugs->freebsd-emulation
> Responsible-Changed-By: linimon
> Responsible-Changed-When: Thu Sep 7 01:58:41 UTC 2006
> Responsible-Changed-Why:
> Over to maintainer(s).

FYI, I have three concerns about this patch:

(1) The value of LINUX_SO_PEERCRED is incorrect for Alpha, it should be 18 on
     that platform.

(2) I'm a bit worried about pid not being set, but this may (may) be OK.  On
     Linux, generally speaking you are guaranteed that either you get (0, -1,
     -1) or (pid, uid, gid), but not a blend of both.  As we support the pid
     for SCM_CREDS, we might also consider adding a LOCAL_PEERPID for use by
     the linux emulator to query the remote pid (we'd need to add that where
     the peercred is currently cached though).

(3) LOG_WARNING should perhaps be LOG_DEBUG or something more consistent with
     the res of the linuxulator.

FYI, I'm not sure I like that we just pass all other socket options through to 
getsockopt() without transformation or an error, it seems failure-prone.  We 
may end up returning invalid data, etc, but that's not caused by this patch, 
but a generally poor failure mode in the linuxulator.

Robert N M Watson
Computer Laboratory
University of Cambridge
Comment 4 Marcin Cieslak 2008-09-09 16:09:27 UTC
Hello,

> (1) The value of LINUX_SO_PEERCRED is incorrect for Alpha, it should be 18 on
> that platform.


Well, in the meantime Alpha support is gone...

> (2) I'm a bit worried about pid not being set, but this may (may) be OK. On
> Linux, generally speaking you are guaranteed that either you get (0, -1,
> -1) or (pid, uid, gid), but not a blend of both. As we support the pid
> for SCM_CREDS, we might also consider adding a LOCAL_PEERPID for use by
> the linux emulator to query the remote pid (we'd need to add that where
> the peercred is currently cached though).


Will remote PID always be available?
> 
> (3) LOG_WARNING should perhaps be LOG_DEBUG or something more consistent with
> the res of the linuxulator.


I agree. This should be LOG_DEBUG.

  > FYI, I'm not sure I like that we just pass all other socket options 
through to
> getsockopt() without transformation or an error, it seems failure-prone. We
> may end up returning invalid data, etc, but that's not caused by this patch,
> but a generally poor failure mode in the linuxulator.


I agree. Probably we should explicitly list all supported socket option. 
I think most of the translation layer is coded for "fixing known 
differences" vs. "explicit support for X, Y, Z returning EA, EB or EC".

--Marcin
Comment 5 Dmitry Chagin freebsd_committer freebsd_triage 2009-03-16 18:27:06 UTC
Responsible Changed
From-To: rink->dchagin

grab PR, discussed with rink.
Comment 6 dfilter service freebsd_committer freebsd_triage 2009-05-16 19:42:30 UTC
Author: dchagin
Date: Sat May 16 18:42:18 2009
New Revision: 192203
URL: http://svn.freebsd.org/changeset/base/192203

Log:
  Emulate SO_PEERCRED socket option.
  Temporarily use 0 for pid member as the FreeBSD does not cache remote
  UNIX domain socket peer pid.
  
  PR:		kern/102956
  Reviewed by:	rwatson
  Approved by:	kib (mentor)
  MFC after:	1 month

Modified:
  head/sys/compat/linux/linux_socket.c
  head/sys/compat/linux/linux_socket.h

Modified: head/sys/compat/linux/linux_socket.c
==============================================================================
--- head/sys/compat/linux/linux_socket.c	Sat May 16 18:08:28 2009	(r192202)
+++ head/sys/compat/linux/linux_socket.c	Sat May 16 18:42:18 2009	(r192203)
@@ -1354,7 +1354,9 @@ linux_getsockopt(struct thread *td, stru
 	} */ bsd_args;
 	l_timeval linux_tv;
 	struct timeval tv;
-	socklen_t tv_len;
+	socklen_t tv_len, xulen;
+	struct xucred xu;
+	struct l_ucred lxu;
 	int error, name;
 
 	bsd_args.s = args->s;
@@ -1377,6 +1379,23 @@ linux_getsockopt(struct thread *td, stru
 			    sizeof(linux_tv)));
 			/* NOTREACHED */
 			break;
+		case LOCAL_PEERCRED:
+			if (args->optlen != sizeof(lxu))
+				return (EINVAL);
+			xulen = sizeof(xu);
+			error = kern_getsockopt(td, args->s, bsd_args.level,
+			    name, &xu, UIO_SYSSPACE, &xulen);
+			if (error)
+				return (error);
+			/*
+			 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
+			 */
+			lxu.pid = 0;
+			lxu.uid = xu.cr_uid;
+			lxu.gid = xu.cr_gid;
+			return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
+			/* NOTREACHED */
+			break;
 		default:
 			break;
 		}

Modified: head/sys/compat/linux/linux_socket.h
==============================================================================
--- head/sys/compat/linux/linux_socket.h	Sat May 16 18:08:28 2009	(r192202)
+++ head/sys/compat/linux/linux_socket.h	Sat May 16 18:42:18 2009	(r192203)
@@ -90,4 +90,10 @@
 #define	LINUX_AF_APPLETALK	5
 #define	LINUX_AF_INET6		10
 
+struct l_ucred {
+	uint32_t	pid;
+	uint32_t	uid;
+	uint32_t	gid;
+};
+
 #endif /* _LINUX_SOCKET_H_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 7 Dmitry Chagin freebsd_committer freebsd_triage 2009-05-16 22:50:27 UTC
State Changed
From-To: open->patched

commited to current.
Comment 8 dfilter service freebsd_committer freebsd_triage 2009-06-16 06:06:00 UTC
Author: dchagin
Date: Tue Jun 16 05:05:46 2009
New Revision: 194281
URL: http://svn.freebsd.org/changeset/base/194281

Log:
  MFC r192203:
  
  Emulate SO_PEERCRED socket option.
  Temporarily use 0 for pid member as the FreeBSD does not cache remote
  UNIX domain socket peer pid.
  
  PR:		kern/102956
  Approved by:	kib (mentor)

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/compat/linux/linux_socket.c
  stable/7/sys/compat/linux/linux_socket.h
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/ath/ath_hal/   (props changed)

Modified: stable/7/sys/compat/linux/linux_socket.c
==============================================================================
--- stable/7/sys/compat/linux/linux_socket.c	Tue Jun 16 03:51:38 2009	(r194280)
+++ stable/7/sys/compat/linux/linux_socket.c	Tue Jun 16 05:05:46 2009	(r194281)
@@ -1159,7 +1159,9 @@ linux_getsockopt(struct thread *td, stru
 	} */ bsd_args;
 	l_timeval linux_tv;
 	struct timeval tv;
-	socklen_t tv_len;
+	socklen_t tv_len, xulen;
+	struct xucred xu;
+	struct l_ucred lxu;
 	int error, name;
 
 	bsd_args.s = args->s;
@@ -1182,6 +1184,23 @@ linux_getsockopt(struct thread *td, stru
 			    sizeof(linux_tv)));
 			/* NOTREACHED */
 			break;
+		case LOCAL_PEERCRED:
+			if (args->optlen != sizeof(lxu))
+				return (EINVAL);
+			xulen = sizeof(xu);
+			error = kern_getsockopt(td, args->s, bsd_args.level,
+			    name, &xu, UIO_SYSSPACE, &xulen);
+			if (error)
+				return (error);
+			/*
+			 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
+			 */
+			lxu.pid = 0;
+			lxu.uid = xu.cr_uid;
+			lxu.gid = xu.cr_gid;
+			return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
+			/* NOTREACHED */
+			break;
 		default:
 			break;
 		}

Modified: stable/7/sys/compat/linux/linux_socket.h
==============================================================================
--- stable/7/sys/compat/linux/linux_socket.h	Tue Jun 16 03:51:38 2009	(r194280)
+++ stable/7/sys/compat/linux/linux_socket.h	Tue Jun 16 05:05:46 2009	(r194281)
@@ -59,4 +59,10 @@
 #define	LINUX_AF_APPLETALK	5
 #define	LINUX_AF_INET6		10
 
+struct l_ucred {
+	uint32_t	pid;
+	uint32_t	uid;
+	uint32_t	gid;
+};
+
 #endif /* _LINUX_SOCKET_H_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 9 Dmitry Chagin freebsd_committer freebsd_triage 2010-07-05 21:27:24 UTC
State Changed
From-To: patched->closed


Feedback timeout. 6.1 still don't have SO_PEERCRED support.
Comment 10 roel 2010-09-24 14:16:19 UTC
This PR was opened in 2006 by Marcin Cieslak. His reason was
Oracle XE not running correctly due to the usage of the
linux SO_PEERCRED option. He wrote a patch for this that
worked without any known problems.

This patch was rewritten by dchagin in May and June 2009.
He changed one significant detail.

While in the original patch the following comparison was
made:

+                if (optlen < sizeof(linux_ucred))
+                        return (EFAULT);

dchagin rewrote this to:

+                        if (args->optlen != sizeof(lxu))
+                                return (EINVAL);

However, due to this change, Oracle XE's setsockopt call
for SO_PEERCRED will fail with EINVAL. For Oracle to
work successfully, the patch should contain:

+                        if (args->optlen < sizeof(lxu))
+                                return (EINVAL);

It seems that Oracle passes in a structure that is larger than
the struct linux_ucred defined in this patch. Why? Don't know,
haven't had time to debug this in detail.

As Oracle XE would not run on a new system with 8-STABLE I
investigated and by comparing both the old patch and current
code I quickly came to the conclusion above. Changing the
comparison in linux_socket back to a smaller-than comparison
solved the problem.

The original patch has been running in a production situation
for a couple of years now and no problems have surfaced.
Checking that the structure is sufficiently large should
guarantee stability. There is no need for the kernel to return
EINVAL if a larger structure was passed in.

If requested, I am willing to investigate further.

Kind regards,

Roel Bouwman.
-- 
QSP Internet Services /
Quality Service Provider BV
Postbus 9340
5000 HH Tilburg
The Netherlands
Tel. +31 135810451
Fax. +31 135810454
Mob. +31 618782702
E-mail: roel@qsp.nl
Comment 11 commit-hook freebsd_committer freebsd_triage 2017-03-18 18:31:22 UTC
A commit references this bug:

Author: dchagin
Date: Sat Mar 18 18:31:04 UTC 2017
New revision: 315503
URL: https://svnweb.freebsd.org/changeset/base/315503

Log:
  As noted by Roel Bouwman Linux allows a large buffer size than the
  struct ucred size. Fix this.

  PR:		102956
  Reported by:	Roel Bouwman <roel at qsp nl>
  MFC after:	1 week

Changes:
  head/sys/compat/linux/linux_socket.c
Comment 12 commit-hook freebsd_committer freebsd_triage 2017-03-25 14:27:01 UTC
A commit references this bug:

Author: dchagin
Date: Sat Mar 25 14:26:46 UTC 2017
New revision: 315954
URL: https://svnweb.freebsd.org/changeset/base/315954

Log:
  MFC r315503:

  As noted by Roel Bouwman Linux allows a large buffer size than the
  struct ucred size. Fix this.

  PR:           102956

Changes:
_U  stable/11/
  stable/11/sys/compat/linux/linux_socket.c