Re: knfsd 1.5 is released

Olaf Kirch (okir@monad.swb.de)
Mon, 4 Oct 1999 10:45:20 +0200


On Sat, Oct 02, 1999 at 08:33:14AM +0100, David Woodhouse wrote:
> On Thu, 30 Sep 1999, Olaf Kirch wrote:
> > With David's queue-the-request-and-redo-it approach, there's
> > the potential for a memory DoS.
>
> That's not my approach. Ideally, I'd like to chuck the whole request up
> the pipe to mountd. mountd can then either return ESTALE itself or stick
> the request back into the kernel's incoming request queue, as it sees fit.

Well, wherever you store the request while mountd is pondering whether
the client is legit or not, you need memory for it. Sending packets
at twice the rate at which mountd can ponder does create a problem :)

> That way, we don't really need the negative export entries,

Negative entries aren't needed at all when you decide to drop all
illegitimate requests anyway.

> The reason I didn't do this straight away was because it requires rather
> fundamental hacking to the RPC layer, to allow mountd to respond on behalf
> of nfsd, and to allow mountd to inject requests into nfsd's incoming
> queue.

The hacking is not that fundamental. In fact, the request
doesn't have to travel up to mountd at all.
Do this in sunrpc/svcsock.c:

struct deferred_req {
struct deferred_req * next;
struct sockaddr_in addr;
struct svc_buf args;
};
static struct deferred_req * deferred;
static struct deferred_req * deferred_ready;

/*
* New function defer
*/
void
svc_defer(struct svc_rqst *rqstp)
{
struct deferred_req *dreq;
struct svc_buf *arg;

arg = &rqstp->rq_argbuf;

/* Create a copy of the argument buffer */
dreq = kmalloc(sizeof(*dreq) + arg->len, GFP_KERNEL);
dreq->addr = rqstp->rq_addr;
dreq->args.area = (dreq + 1);
dreq->args .... more init stuff
memcpy(dreq->args.area, arg->area, arg->len);

/* Stick into deferred queue */

svc_sock_release(rqstp);
}

/*
* New function, called when mountd pushes new export entry into kernel
*/
void
svc_undefer(struct in_addr clnt)
{
/* Move all requests originating from clnt
* from deferred to deferred_ready
*/
}

/*
* And finally patch svc_recv to first look into deferred_ready
*/
int
svc_recv(...)
{

again:
/* Extract deferred request from deferred_ready */
if ((dreq = deferred_ready) != NULL) {
/* Copy request */
struct svc_buf *arg, *darg;

arg = &rqstp->rq_argbuf;
darg = &dreq->args;
memcpy(arg->base, darg->base, darg->len);
arg->len = darg->len;

rqstp->rq_sock = NULL;
rqstp->rq_addr = dreq->addr;

kfree(dreq);
goto gotit;
}

/* Normal recvfrom */

gotit:
/* Normal flags, XID copying... but don't bump stats->netcnt */
}

Still, I vote for just dropping the request, and wait for the
client to retransmit. It's KISS.

> There should be a way of selectively disabling the cached entries which
> are obsoleted, rather than just trashing the cache entirely.

Which can be very very difficult. Consider

/local *.foo.edu(ro) @trusted(rw) \
safe.foo.edu(rw,no_root_squash)

And me typing on the command line exportfs -u @trusted:/local.
Client safe will remain with maximum trust, some clients in @trusted
(those not in the foo.edu domain) will have to be removed completely,
and some will have to be demoted from rw to ro.

I've twice written the kind of code that does this -- once for unfsd and
once for knfsd. Just nuking the cache sounds like a good alternative
to me :-)

Olaf

-- 
Olaf Kirch         |  --- o --- Nous sommes du soleil we love when we play
okir@monad.swb.de  |    / | \   sol.dhoop.naytheet.ah kin.ir.samse.qurax
okir@caldera.de    +-------------------- Why Not?! -----------------------
         UNIX, n.: Spanish manufacturer of fire extinguishers.            
	  The skey oracle says: NIBS RUB TECH LIST LEFT OLAF

- 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/