lkml.org 
[lkml]   [1999]   [Aug]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: RPC and more than 16-groups...
On Sat, Aug 07, 1999 at 02:17:50AM +0200, Mattias.Gronlund wrote:
> I think there is one problem with your patch, as I understand
> it it lower the risk of missing to send the needed gid, but
> it doesn't eliminate it.
No, it is (should be) an exact solution and not a heuristic: the
risk should be zero within certain clearly defined boundaries.
The idea is as follows (feel free to shoot at it):

First, my solution does not tackle gid changes on open files,
e.g. between two reads. UNIX does no permission checking on
read calls but NFS does on RPC basis (it is stateless): NFS has
to remember the credentials during the open(). There have been
bugs in this area in many UNIXes. Symptom is that redirecting the
output of setuid programs can fail. This bug is not present in Linux
nowadays. Complexity and being uncertain if it is solvable without
great pain in performance I decided not to track gid changes on
open files. Second, I assume that the server does UNIX style
permission checking (RPC does AUTH_UNIX in this case).

Now let's consider some of the other FS operations at user level:
open()
mkdir()
mknod()
link()
symlink()
unlink()
rmdir()
rename()
chown() /* for changing the gid on a file */

Between any of these calls the secondary group list and effective
uids/gids may change due to other system calls. So, NFS/RPC has to
refresh the credential for any of these calls. So, when the
RPC gid cache is updated at the start of the corresponding NFS
operation it should work. Now all these system calls operate on
pathnames and every component can have a different group id.
In the kernel every component results in an nfs_lookup() and here
the RPC gid cache is updated for a path component. The nfs_open()
still updates the RPC gid cache though in my patch.

There are some big changes in NFS between a number of kernel
versions so I decided to wait for a more stable NFS source
before considering the following potential weaknesses again:

- Some day, nfs_lookup() might go to the server in such a
way that the credential is not updated for changes in
the group id cache. If uid/gid can never change
between nfs_lookup() calls then NFS/RPC could decide
to do so but it breaks the gid cache. In that case
a small adjustment has to be made to NFS/RPC.
- nfs_open() might not need to update the RPC gid cache
because it's all done in nfs_lookup().

In practice this is not very likely to cause a problem. After
all, the RPC cache is 16 gids large and without this cache
the extra groups are simply discarded. Of course there may be
rpc_register_group() calls missing at other places which simply
escaped my attention. Also, I don't like memmoves but I doubt
if there is a performance problem in practice. There are lots
of things going on and the RPC cache will never be bigger than
16: it just makes no sense because it is a hard protocol limit.

> My proposal is that there should be an extra operation
> retry added to rpc_authops. The retry-operation should then
> be called from net/sunrpc/clnt.c:call_decode to decide if the
> request should be retried. At the moment there is a suid fix
> there, but I beleve that it should be possible to extend that
> "fix" to try a new set of credentials until all groups are
> tested.
Something similar was one of my first ideas: try all groups in some
intelligent way. But I have very bad feelings about software which
just tries things. If there is an exact solution we should go for
that one and if not, we should forget all about my patch. I can
imagine situations where software "tries" something but not here.
Undeterministic behavior is a terrible thing.

> There still is a need for a cache, but it might be better with
> a simple LRU, because if I understands your implementation
> a gid that is referenced alot at the begining of the session
> will get stuck in the cache for a long time even if it isn't
> used later.
No, I think not. It is a real LRU and not a LFU (least frequently
used). Look what happens when a gid is already in the cache. Only
giduse[] is updated to give the most recent group the highest
number (== #groups in the RPC gid cache). Suppose the cache
contains:

groups[] = {1001,1002,1003}
giduse[] = {3,1,2}

and group 1002 is registered again. All giduse[] numbers higher
than giduse[1] will be decremented and giduse[1] will be set to 3:

groups[] = {1001,1002,1003}
giduse[] = {2,3,1}

Repeat this procedure and you can see that nothing happens anymore.
When a new groups is added giduse[] is decremented entirely and the
entry which becomes zero will be set to rpc_ngroups for the new
group.

linux-kernel readers: please don't flame me if I'm dead wrong
in my perceptions of the kernel but explain it if it's not
too much trouble.

Regards,

--
Frank

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:53    [W:0.080 / U:0.548 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site