Bug 481422

Summary: rpcbind without -i restricts set/unset to root user on localhost, so pmap_set fails for non-root users unless -i is used
Product: [Fedora] Fedora Reporter: Andrew J. Schorr <aschorr>
Component: rpcbindAssignee: Steve Dickson <steved>
Status: CLOSED CURRENTRELEASE QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: medium Docs Contact:
Priority: low    
Version: rawhideCC: steved
Target Milestone: ---Keywords: Reopened
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
: 731542 (view as bug list) Environment:
Last Closed: 2012-08-20 15:05:12 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 731542    
Attachments:
Description Flags
Add new -c, -r, and -u options to allow fine-tuning of security holes.
none
Patch the spec file to apply the new security patch none

Description Andrew J. Schorr 2009-01-24 15:37:14 UTC
Description of problem:
By default in Fedora 10, rpcbind runs with no options.  In this mode,
it denies set/unset requests unless the is_loopback function returns
true.  But is_loopback does more than its name would suggest: it
requires that the call arrive from a loopback IP address and from
a reserved port.  This means that programs not running as root are
unable to register services with rpcbind.  But if we add the -i option
to rpcbind, then it allows set/unset calls from remote hosts in
addition to non-root local users.


Version-Release number of selected component (if applicable):
0.1.7-1.fc10

How reproducible:
Allow rpcbind to start normally without options, and then try to
run a program as a non-root user that calls pmap_set.  The call
will fail.

Steps to Reproduce:
1. Run rpcbind without any options.
2. As a non-root user, run a program that calls pmap_set
3.
  
Actual results:
pmap_set returns 0 for failure and fails to register the service.

Expected results:
pmap_set should succeed in registering the service.

Additional info:
The man page claims that the -i option is just to allow access
from remote hosts, and that recompiling code should solve the
problem.  But in fact, recompiling the code does not solve the
problem for non-root users, since the current glibc pmap_set
call will still fail.  At the very least, the man page should
be corrected to indicate what -i actually does and that
recompilation will not solve the problem for non-root users.
A better solution would be to break the -i option into two
finer-grained options, one to allow SET/UNSET from remote hosts,
and another to allow SET/UNSET from non-reserved ports accessible
to non-root users.

Comment 1 Bug Zapper 2009-11-18 10:51:07 UTC
This message is a reminder that Fedora 10 is nearing its end of life.
Approximately 30 (thirty) days from now Fedora will stop maintaining
and issuing updates for Fedora 10.  It is Fedora's policy to close all
bug reports from releases that are no longer maintained.  At that time
this bug will be closed as WONTFIX if it remains open with a Fedora 
'version' of '10'.

Package Maintainer: If you wish for this bug to remain open because you
plan to fix it in a currently maintained version, simply change the 'version' 
to a later Fedora version prior to Fedora 10's end of life.

Bug Reporter: Thank you for reporting this issue and we are sorry that 
we may not be able to fix it before Fedora 10 is end of life.  If you 
would still like to see this bug fixed and are able to reproduce it 
against a later version of Fedora please change the 'version' of this 
bug to the applicable version.  If you are unable to change the version, 
please add a comment here and someone will do it for you.

Although we aim to fix as many bugs as possible during every release's 
lifetime, sometimes those efforts are overtaken by events.  Often a 
more recent Fedora release includes newer upstream software that fixes 
bugs or makes them obsolete.

The process we are following is described here: 
http://fedoraproject.org/wiki/BugZappers/HouseKeeping

Comment 2 Andrew J. Schorr 2009-11-18 16:08:34 UTC
The source code in src/security.c is the same in version 0.2.0 in Fedora 12 as it was in version 0.1.7 in Fedora 10.  So the bug is still there.

Comment 3 Steve Dickson 2010-12-06 14:21:06 UTC
(In reply to comment #0)
> Description of problem:
> By default in Fedora 10, rpcbind runs with no options.  In this mode,
> it denies set/unset requests unless the is_loopback function returns
> true.  But is_loopback does more than its name would suggest: it
> requires that the call arrive from a loopback IP address and from
> a reserved port.  This means that programs not running as root are
> unable to register services with rpcbind.  But if we add the -i option
> to rpcbind, then it allows set/unset calls from remote hosts in
> addition to non-root local users.
> 
> 
> Version-Release number of selected component (if applicable):
> 0.1.7-1.fc10
> 
> How reproducible:
> Allow rpcbind to start normally without options, and then try to
> run a program as a non-root user that calls pmap_set.  The call
> will fail.
> 
> Steps to Reproduce:
> 1. Run rpcbind without any options.
> 2. As a non-root user, run a program that calls pmap_set
> 3.
> 
> Actual results:
> pmap_set returns 0 for failure and fails to register the service.
> 
> Expected results:
> pmap_set should succeed in registering the service.
> 
> Additional info:
> The man page claims that the -i option is just to allow access
> from remote hosts, and that recompiling code should solve the
> problem.  But in fact, recompiling the code does not solve the
> problem for non-root users, since the current glibc pmap_set
> call will still fail.  At the very least, the man page should
> be corrected to indicate what -i actually does and that
> recompilation will not solve the problem for non-root users.
> A better solution would be to break the -i option into two
> finer-grained options, one to allow SET/UNSET from remote hosts,
> and another to allow SET/UNSET from non-reserved ports accessible
> to non-root users.
The '-i' flag has nothing to do with root and non-root users.
All that flag does is allow request from another network interface
other than the loopback interface. Basically what the man page
says.... 

Now if the glibc clnt_call() does not allow non-root calls, that's
not a rpcbind problem... Open a bz against glibc... but I would 
suggested try using the cln_call() in libtirpc.

Comment 4 Andrew J. Schorr 2010-12-06 17:47:44 UTC
I respectfully disagree.  If you look in rpcbind.c:main, you will see
that the -i flag results in setting insecure = 1.  And if you then grep
for where the insecure flag is reference, you will see this in
security.c:check_access:

                if (!insecure && !is_loopback(caller)) {
                      <deny the request>
                }

And if you look in the is_loopback function in the same file, you will see this:

                return ((sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) &&
                    (ntohs(sin->sin_port) < IPPORT_RESERVED));

In other words, if -i is not specified, then requests are accepted only
from the local host and from a reserved port.   Since reserved ports are
available only to root, this means that non-root programs are unable
to register services with rpcbind, even when run on the local host.

The man page says that the purpose of the "-i" flag is to allow calls
from any host.  It does not mention anything about reserved ports.

Turning on -i to enable local programs to register services is a security
hole -- there is no need to open this up to remote programs.

Did you read my problem report carefully?   It's been almost 2 years now...

Regards,
Andy

Comment 5 Steve Dickson 2010-12-06 18:15:27 UTC
(In reply to comment #4)
> I respectfully disagree.  If you look in rpcbind.c:main, you will see
> that the -i flag results in setting insecure = 1.  And if you then grep
> for where the insecure flag is reference, you will see this in
> security.c:check_access:
> 
>                 if (!insecure && !is_loopback(caller)) {
>                       <deny the request>
>                 }
> 
> And if you look in the is_loopback function in the same file, you will see
> this:
> 
>                 return ((sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) &&
>                     (ntohs(sin->sin_port) < IPPORT_RESERVED));
> 
> In other words, if -i is not specified, then requests are accepted only
> from the local host and from a reserved port.   Since reserved ports are
> available only to root, this means that non-root programs are unable
> to register services with rpcbind, even when run on the local host.
Yes.. I do now see you point... 

> 
> The man page says that the purpose of the "-i" flag is to allow calls
> from any host.  It does not mention anything about reserved ports.
True...

> 
> Turning on -i to enable local programs to register services is a security
> hole -- there is no need to open this up to remote programs.
I agree... But it sounds its there for backward compatibility...
  
> 
> Did you read my problem report carefully? 
Obviously not close enough.. ;-) So in your description you're suggesting
having two options. One to allow local non-root set/unsets and the other
to allow remote machines do sets/unsets... As you have already pointed
out the latter is a huge security hole... So I'm thinking it would 
make sense to deprecate the -i flag. Then possibly introduce a new
-I flag allowing non-root sets/unsets...

Looking at other implementations, these options do not exist, which
could be an argument for doing neither...    

Just curious, why do you need non-root sets/unsets?

Thank you for your patiences....

Comment 6 Steve Dickson 2010-12-06 18:26:12 UTC
The easiest thing to do is simply update the man page to
more accurate:

diff --git a/man/rpcbind.8 b/man/rpcbind.8
index c5b8fb7..3686969 100644
--- a/man/rpcbind.8
+++ b/man/rpcbind.8
@@ -116,7 +116,8 @@ Normally
 accepts these requests only from the loopback interface for security reasons.
 This change is necessary for programs that were compiled with earlier
 versions of the rpc library and do not make those requests using the
-loopback interface.
+loopback interface. Note, the requests must come from a local process
+since connection has to bound on a privileged port.
 .It Fl l
 Turn on libwrap connection logging.
 .It Fl s

Comment 7 Andrew J. Schorr 2010-12-06 18:56:30 UTC
If the goal is merely to correct the man page, I'd say this language is
more accurate:

   In the absence of the -i option, calls are accepted only from privileged
   ports via the loopback interface.

But as you agreed, -i is a big security hole for normal usage cases where simply
allowing access to local, but non-superuser, processes is needed.

I have many such programs on my system.  We used the SunOS portmapper heavily
back in the 90s to advertise local services.  I suppose nobody else uses
rpcbind any more, otherwise somebody else would have complained.

If I were to supply a patch for the code to add a new -I flag, would it be
considered? Or is it a waste of time?

Regards,
Andy

Comment 8 Steve Dickson 2010-12-06 19:32:04 UTC
(In reply to comment #7)
> If the goal is merely to correct the man page, I'd say this language is
> more accurate:
> 
>    In the absence of the -i option, calls are accepted only from privileged
>    ports via the loopback interface.
Sounds fine... 

> 
> But as you agreed, -i is a big security hole for normal usage cases where
> simply
> allowing access to local, but non-superuser, processes is needed.
> 
> I have many such programs on my system.  We used the SunOS portmapper heavily
> back in the 90s to advertise local services.  I suppose nobody else uses
> rpcbind any more, otherwise somebody else would have complained.
> 
> If I were to supply a patch for the code to add a new -I flag, would it be
> considered? Or is it a waste of time?
No guarantees... but there I know there has been some talk about this
in the past... I think it would be a good discussion to have... 

If you are so incline.. Post the patches to linux-nfs.org and
lets start the discussion....

Comment 9 Andrew J. Schorr 2010-12-09 20:43:29 UTC
Created attachment 467840 [details]
Add new -c, -r, and -u options to allow fine-tuning of security holes.

This patch adds -c, -r, and -u options to break down the functionality currently provided by the -i option.  This allows the user to choose how much "insecurity" to introduce.

Comment 10 Andrew J. Schorr 2010-12-09 20:44:36 UTC
Created attachment 467841 [details]
Patch the spec file to apply the new security patch

To be used in conjunction with the security patch to build the new rpm.

Comment 11 Steve Dickson 2012-07-24 19:11:12 UTC
I think this upstream patch is what you are looking for

commit 1d9fba5b631b517094c85a80f45f6f7ba1665e2a
Author: Olaf Kirch <okir>
Date:   Wed Mar 16 14:19:37 2011 -0400

    Make is_loopback check more permissive
    
    This patch relaxes the is_loopback() check to its original meaning;
    i.e. verify that the caller is local. We no longer check whether
    the source port is privileged, for a number of reasons.
    
    1) The existing check did not allow *any* non-root program to register
       a services via UDP or TCP transport. It did however allow
       *any* registration when using the AF_LOCAL transport.
    
    2) Unregistration of services is only possible if the caller has
       the same "user name", i.e.
        "superuser"
                for root (when connecting through AF_LOCAL sockets,
                or when using pmap_set with a privileged port)
        numeric uid
                for non-root users when connecting through AF_LOCAL
                sockets
        "unknown"
                for all other users
    
    This seems safe enough to allow the removal of the privileged port
    check in is_localhost.
    
    Signed-off-by: Olaf Kirch <okir>
    Signed-off-by: Steve Dickson <steved>

diff --git a/src/security.c b/src/security.c
index 07c8933..d272f74 100644
--- a/src/security.c
+++ b/src/security.c
@@ -138,8 +138,7 @@ is_loopback(struct netbuf *nbuf)
                                  "Checking caller's adress (port = %d)\n",
                                  ntohs(sin->sin_port));
 #endif
-               return ((sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) &&
-                   (ntohs(sin->sin_port) < IPPORT_RESERVED));
+               return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK));
 #ifdef INET6
        case AF_INET6:
                if (!oldstyle_local)
@@ -151,10 +150,9 @@ is_loopback(struct netbuf *nbuf)
                                  "Checking caller's adress (port = %d)\n",
                                  ntohs(sin6->sin6_port));
 #endif
-               return ((IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) ||
+               return (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) ||
                         (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) &&
-                         sin6->sin6_addr.s6_addr32[3] == htonl(INADDR_LOOPBACK)
-                       (ntohs(sin6->sin6_port) < IPV6PORT_RESERVED));
+                         sin6->sin6_addr.s6_addr32[3] == htonl(INADDR_LOOPBACK)
 #endif
        case AF_LOCAL:
                return 1;

Comment 12 Steve Dickson 2012-08-20 15:05:12 UTC
(In reply to comment #11)
> I think this upstream patch is what you are looking for
> 
> commit 1d9fba5b631b517094c85a80f45f6f7ba1665e2a
> Author: Olaf Kirch <okir>
> Date:   Wed Mar 16 14:19:37 2011 -0400
> 
>     Make is_loopback check more permissive

This patch went in with the 

* Thu Mar 17 2011 Steve Dickson <steved> - 0.2.0-11
- Updated to the latest upstream release: rpcbind-0_2_1-rc3