PERFORCE change 105906 for review

Wojciech A. Koszek wkoszek at freebsd.org
Wed Sep 27 05:27:22 PDT 2006


On sob, wrz 09, 2006 at 06:56:09 +0000, Alexander Leidinger wrote:
> http://perforce.freebsd.org/chv.cgi?CH=105906
> 
> Change 105906 by netchild at netchild_magellan on 2006/09/09 18:56:01
> 
> 	       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.
> 	
> 	PR:		102956
> 	Submitted by:	Marcin Cieslak <saper at SYSTEM.PL>
> 
> Affected files ...
> 
> .. //depot/projects/linuxolator/src/sys/amd64/linux32/linux.h#2 edit
> .. //depot/projects/linuxolator/src/sys/compat/linux/linux_socket.c#2 edit
> .. //depot/projects/linuxolator/src/sys/i386/linux/linux.h#2 edit
> 
> Differences ...
> 
> ==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux.h#2 (text+ko) ====
> 
> @@ -659,6 +659,7 @@
>  #define	LINUX_SO_NO_CHECK	11
>  #define	LINUX_SO_PRIORITY	12
>  #define	LINUX_SO_LINGER		13
> +#define	LINUX_SO_PEERCRED	17
>  
>  #define	LINUX_IP_TOS		1
>  #define	LINUX_IP_TTL		2
> 
> ==== //depot/projects/linuxolator/src/sys/compat/linux/linux_socket.c#2 (text+ko) ====
> 
> @@ -35,6 +35,7 @@
>  
>  #include <sys/param.h>
>  #include <sys/proc.h>
> +#include <sys/syslog.h>
>  #include <sys/systm.h>
>  #include <sys/sysproto.h>
>  #include <sys/fcntl.h>
> @@ -49,6 +50,7 @@
>  #include <sys/syscallsubr.h>
>  #include <sys/uio.h>
>  #include <sys/syslog.h>
> +#include <sys/un.h>
>  
>  #include <netinet/in.h>
>  #include <netinet/in_systm.h>
> @@ -292,6 +294,8 @@
>  		return (SO_OOBINLINE);
>  	case LINUX_SO_LINGER:
>  		return (SO_LINGER);
> +	case LINUX_SO_PEERCRED:
> +		return (LOCAL_PEERCRED);
>  	}
>  	return (-1);
>  }
> @@ -1171,7 +1175,13 @@
>  		caddr_t val;
>  		int *avalsize;
>  	} */ bsd_args;
> -	int error, name;
> +	struct linux_ucred {
> +		uint32_t pid;
> +		uint32_t uid;
> +		uint32_t gid;
> +	} linux_ucred;
> +	struct xucred xuc;
> +	int error, name, optlen, rc, xuclen;
>  
>  	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
>  		return (error);
> @@ -1193,12 +1203,43 @@
>  		name = -1;
>  		break;
>  	}
> -	if (name == -1)
> +	if (name == -1) {
> +		log(LOG_WARNING, "LINUX: 'getsockopt' level=0x%04x"
> +			"optname=0x%04x not implemented\n",
> +			linux_args.level, linux_args.optname);
>  		return (EINVAL);
> +	};
>  
>  	bsd_args.name = name;
> -	bsd_args.val = PTRIN(linux_args.optval);
> -	bsd_args.avalsize = PTRIN(linux_args.optlen);
> +	if (bsd_args.level == SOL_SOCKET && name == LOCAL_PEERCRED) {
> +		if ((error = copyin(PTRIN(linux_args.optval),
> +			&linux_ucred, sizeof(linux_ucred))))
> +			return (error);
> +		if ((error = copyin(PTRIN(linux_args.optlen),
> +			&optlen, sizeof(optlen))))
> +			return (error);
> +		if (optlen < sizeof(linux_ucred))
> +			return (EFAULT);
> +		xuclen = sizeof(xuc);
> +		if ((rc = error = kern_getsockopt(td, bsd_args.s,
> +			0, bsd_args.name,
> +			(caddr_t) &xuc, UIO_SYSSPACE, &xuclen)))
> +			return (error);
> +		if (xuc.cr_version != XUCRED_VERSION)
> +			return (EINVAL);
> +		/* XXX get PID */
> +		linux_ucred.pid = 0;
> +		linux_ucred.uid = xuc.cr_uid;
> +		linux_ucred.gid = xuc.cr_gid;
> +		if ((error = copyout(&linux_ucred,
> +			PTRIN(linux_args.optval), sizeof(linux_ucred))))
> +			return (error);
> +		return (rc);
> +	} else {
> +		bsd_args.val = PTRIN(linux_args.optval);
> +		bsd_args.avalsize = PTRIN(linux_args.optlen);
> +		return (getsockopt(td, &bsd_args));
> +	}
>  
>  	if (name == IPV6_NEXTHOP) {
>  		error = getsockopt(td, &bsd_args);
> 
> ==== //depot/projects/linuxolator/src/sys/i386/linux/linux.h#2 (text+ko) ====
> 
> @@ -633,6 +633,7 @@
>  #define	LINUX_SO_NO_CHECK	11
>  #define	LINUX_SO_PRIORITY	12
>  #define	LINUX_SO_LINGER		13
> +#define	LINUX_SO_PEERCRED	17
>  
>  #define	LINUX_IP_TOS		1
>  #define	LINUX_IP_TTL		2

I'm not sure if this patch is correct. I looked briefly over Marcin's
report, and the code path responsible for handling translation between what
Linux relies on and what FreeBSD requires. We tend to push the whole job in
sogetopt() function, which in turn deploys uipc_ctloutput() function. With
this mechanism, I belive it is possible to handle LOCAL_PEERCRED without a
problem. The only exception is that the SOL_SOCKET has to be mapped to other
value, like 0. This is what we actually do in getpeereid() case:

	int
	getpeereid(int s, uid_t *euid, gid_t *egid)
	{
		struct xucred xuc;
		socklen_t xuclen;
		int error;

		xuclen = sizeof(xuc);
		error = getsockopt(s, 0, LOCAL_PEERCRED, &xuc, &xuclen);
		if (error != 0)
			return (error);
		if (xuc.cr_version != XUCRED_VERSION)
			return (EINVAL);
		*euid = xuc.cr_uid;
		*egid = xuc.cr_gid;
		return (0);
	}

-- 
Wojciech A. Koszek
wkoszek at FreeBSD.org
http://FreeBSD.czest.pl/dunstan/


More information about the p4-projects mailing list