diff mbox series

[1/1] nfsd: prevent states_show() from using invalid stateids

Message ID 20240823141401.71740-1-okorniev@redhat.com (mailing list archive)
State New
Headers show
Series [1/1] nfsd: prevent states_show() from using invalid stateids | expand

Commit Message

Olga Kornievskaia Aug. 23, 2024, 2:14 p.m. UTC
states_show() relied on sc_type field to be of valid type
before calling into a subfunction to show content of a
particular stateid. But from commit 3f29cc82a84c we
split the validity of the stateid into sc_status and no longer
changed sc_type to 0 while unhashing the stateid. This
resulted in kernel oopsing as something like
nfs4_show_open() would derefence sc_file which was NULL.

To reproduce: mount the server with 4.0, read and close
a file and then on the server cat /proc/fs/nfsd/clients/2/states

[  513.590804] Call trace:
[  513.590925]  _raw_spin_lock+0xcc/0x160
[  513.591119]  nfs4_show_open+0x78/0x2c0 [nfsd]
[  513.591412]  states_show+0x44c/0x488 [nfsd]
[  513.591681]  seq_read_iter+0x5d8/0x760
[  513.591896]  seq_read+0x188/0x208
[  513.592075]  vfs_read+0x148/0x470
[  513.592241]  ksys_read+0xcc/0x178

Fixes: 3f29cc82a84c ("nfsd: split sc_status out of sc_type")
Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
---
 fs/nfsd/nfs4state.c | 3 +++
 1 file changed, 3 insertions(+)

Comments

Jeff Layton Aug. 23, 2024, 2:40 p.m. UTC | #1
On Fri, 2024-08-23 at 10:14 -0400, Olga Kornievskaia wrote:
> states_show() relied on sc_type field to be of valid type
> before calling into a subfunction to show content of a
> particular stateid. But from commit 3f29cc82a84c we
> split the validity of the stateid into sc_status and no longer
> changed sc_type to 0 while unhashing the stateid. This
> resulted in kernel oopsing as something like
> nfs4_show_open() would derefence sc_file which was NULL.
> 
> To reproduce: mount the server with 4.0, read and close
> a file and then on the server cat /proc/fs/nfsd/clients/2/states
> 
> [  513.590804] Call trace:
> [  513.590925]  _raw_spin_lock+0xcc/0x160
> [  513.591119]  nfs4_show_open+0x78/0x2c0 [nfsd]
> [  513.591412]  states_show+0x44c/0x488 [nfsd]
> [  513.591681]  seq_read_iter+0x5d8/0x760
> [  513.591896]  seq_read+0x188/0x208
> [  513.592075]  vfs_read+0x148/0x470
> [  513.592241]  ksys_read+0xcc/0x178
> 
> Fixes: 3f29cc82a84c ("nfsd: split sc_status out of sc_type")
> Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
> ---
>  fs/nfsd/nfs4state.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index c3def49074a4..8351724b8a43 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -2907,6 +2907,9 @@ static int states_show(struct seq_file *s, void *v)
>  {
>  	struct nfs4_stid *st = v;
>  
> +	if (!st->sc_file)
> +		return 0;
> +
>  	switch (st->sc_type) {
>  	case SC_TYPE_OPEN:
>  		return nfs4_show_open(s, st);

OPEN stateids are the only ones that stick around for a while after
we've closed them out (and that's only for v4.0, IIRC). The others all
only release the file after unhashing.

I think it'd be better to still display that stateid, and just not do
any of the bits in nfs4_show_open that require ->sc_file. We have the
"admin-revoked" string that we display now when SC_STATUS_ADMIN_REVOKED
is set. Maybe we can display "closed" or something in this case?
Chuck Lever III Aug. 23, 2024, 2:42 p.m. UTC | #2
On Fri, Aug 23, 2024 at 10:14:01AM -0400, Olga Kornievskaia wrote:
> states_show() relied on sc_type field to be of valid type
> before calling into a subfunction to show content of a
> particular stateid. But from commit 3f29cc82a84c we
> split the validity of the stateid into sc_status and no longer
> changed sc_type to 0 while unhashing the stateid. This
> resulted in kernel oopsing as something like
> nfs4_show_open() would derefence sc_file which was NULL.
> 
> To reproduce: mount the server with 4.0, read and close
> a file and then on the server cat /proc/fs/nfsd/clients/2/states
> 
> [  513.590804] Call trace:
> [  513.590925]  _raw_spin_lock+0xcc/0x160
> [  513.591119]  nfs4_show_open+0x78/0x2c0 [nfsd]
> [  513.591412]  states_show+0x44c/0x488 [nfsd]
> [  513.591681]  seq_read_iter+0x5d8/0x760
> [  513.591896]  seq_read+0x188/0x208
> [  513.592075]  vfs_read+0x148/0x470
> [  513.592241]  ksys_read+0xcc/0x178
> 
> Fixes: 3f29cc82a84c ("nfsd: split sc_status out of sc_type")
> Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
> ---
>  fs/nfsd/nfs4state.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index c3def49074a4..8351724b8a43 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -2907,6 +2907,9 @@ static int states_show(struct seq_file *s, void *v)
>  {
>  	struct nfs4_stid *st = v;
>  
> +	if (!st->sc_file)
> +		return 0;
> +
>  	switch (st->sc_type) {
>  	case SC_TYPE_OPEN:
>  		return nfs4_show_open(s, st);
> -- 
> 2.43.5
> 

I'll wait for Neil/Jeff's Reviewed-by, but the root cause analysis
seems plausible to me, and I'll plan to apply it for v6.11-rc.

Btw, I noticed this at the tail of states_show():

	/* XXX: copy stateids? */

I'm not really sure, but those won't ever have an sc_file, will
they? Are COPY callback stateids something we want the server to
display in this code? Just musing aloud: maybe the NULL sc_file
check wants to be moved into the show helpers.
Olga Kornievskaia Aug. 23, 2024, 3 p.m. UTC | #3
On Fri, Aug 23, 2024 at 10:40 AM Jeff Layton <jlayton@kernel.org> wrote:
>
> On Fri, 2024-08-23 at 10:14 -0400, Olga Kornievskaia wrote:
> > states_show() relied on sc_type field to be of valid type
> > before calling into a subfunction to show content of a
> > particular stateid. But from commit 3f29cc82a84c we
> > split the validity of the stateid into sc_status and no longer
> > changed sc_type to 0 while unhashing the stateid. This
> > resulted in kernel oopsing as something like
> > nfs4_show_open() would derefence sc_file which was NULL.
> >
> > To reproduce: mount the server with 4.0, read and close
> > a file and then on the server cat /proc/fs/nfsd/clients/2/states
> >
> > [  513.590804] Call trace:
> > [  513.590925]  _raw_spin_lock+0xcc/0x160
> > [  513.591119]  nfs4_show_open+0x78/0x2c0 [nfsd]
> > [  513.591412]  states_show+0x44c/0x488 [nfsd]
> > [  513.591681]  seq_read_iter+0x5d8/0x760
> > [  513.591896]  seq_read+0x188/0x208
> > [  513.592075]  vfs_read+0x148/0x470
> > [  513.592241]  ksys_read+0xcc/0x178
> >
> > Fixes: 3f29cc82a84c ("nfsd: split sc_status out of sc_type")
> > Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
> > ---
> >  fs/nfsd/nfs4state.c | 3 +++
> >  1 file changed, 3 insertions(+)
> >
> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > index c3def49074a4..8351724b8a43 100644
> > --- a/fs/nfsd/nfs4state.c
> > +++ b/fs/nfsd/nfs4state.c
> > @@ -2907,6 +2907,9 @@ static int states_show(struct seq_file *s, void *v)
> >  {
> >       struct nfs4_stid *st = v;
> >
> > +     if (!st->sc_file)
> > +             return 0;
> > +
> >       switch (st->sc_type) {
> >       case SC_TYPE_OPEN:
> >               return nfs4_show_open(s, st);
>
> OPEN stateids are the only ones that stick around for a while after
> we've closed them out (and that's only for v4.0, IIRC). The others all
> only release the file after unhashing.

That's good to know. I had a reproducer for the open but the locking
stateid seem to be not affected by it (and I dont know yet how to
setup a pnfs server).  If only nfs4_show_open() needs to be fixed, I
can do that.

> I think it'd be better to still display that stateid, and just not do
> any of the bits in nfs4_show_open that require ->sc_file. We have the
> "admin-revoked" string that we display now when SC_STATUS_ADMIN_REVOKED
> is set. Maybe we can display "closed" or something in this case?

I'll do as you suggest and then add "closed" if sc_file is null.

Thank you.

> --
> Jeff Layton <jlayton@kernel.org>
>
Olga Kornievskaia Aug. 23, 2024, 3:03 p.m. UTC | #4
On Fri, Aug 23, 2024 at 10:44 AM Chuck Lever <chuck.lever@oracle.com> wrote:
>
> On Fri, Aug 23, 2024 at 10:14:01AM -0400, Olga Kornievskaia wrote:
> > states_show() relied on sc_type field to be of valid type
> > before calling into a subfunction to show content of a
> > particular stateid. But from commit 3f29cc82a84c we
> > split the validity of the stateid into sc_status and no longer
> > changed sc_type to 0 while unhashing the stateid. This
> > resulted in kernel oopsing as something like
> > nfs4_show_open() would derefence sc_file which was NULL.
> >
> > To reproduce: mount the server with 4.0, read and close
> > a file and then on the server cat /proc/fs/nfsd/clients/2/states
> >
> > [  513.590804] Call trace:
> > [  513.590925]  _raw_spin_lock+0xcc/0x160
> > [  513.591119]  nfs4_show_open+0x78/0x2c0 [nfsd]
> > [  513.591412]  states_show+0x44c/0x488 [nfsd]
> > [  513.591681]  seq_read_iter+0x5d8/0x760
> > [  513.591896]  seq_read+0x188/0x208
> > [  513.592075]  vfs_read+0x148/0x470
> > [  513.592241]  ksys_read+0xcc/0x178
> >
> > Fixes: 3f29cc82a84c ("nfsd: split sc_status out of sc_type")
> > Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
> > ---
> >  fs/nfsd/nfs4state.c | 3 +++
> >  1 file changed, 3 insertions(+)
> >
> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > index c3def49074a4..8351724b8a43 100644
> > --- a/fs/nfsd/nfs4state.c
> > +++ b/fs/nfsd/nfs4state.c
> > @@ -2907,6 +2907,9 @@ static int states_show(struct seq_file *s, void *v)
> >  {
> >       struct nfs4_stid *st = v;
> >
> > +     if (!st->sc_file)
> > +             return 0;
> > +
> >       switch (st->sc_type) {
> >       case SC_TYPE_OPEN:
> >               return nfs4_show_open(s, st);
> > --
> > 2.43.5
> >
>
> I'll wait for Neil/Jeff's Reviewed-by, but the root cause analysis
> seems plausible to me, and I'll plan to apply it for v6.11-rc.
>
> Btw, I noticed this at the tail of states_show():
>
>         /* XXX: copy stateids? */
>
> I'm not really sure, but those won't ever have an sc_file, will
> they? Are COPY callback stateids something we want the server to
> display in this code? Just musing aloud: maybe the NULL sc_file
> check wants to be moved into the show helpers.

I can see that the copy stateids still have type NFS4_COPY_STID so
they are not converted to the new type of SC_TYPE. But it just means
we are not displaying them. I'm not sure what happens to sc_file for
copy stateid, I'd need to check.

>
> --
> Chuck Lever
>
Chuck Lever III Aug. 23, 2024, 3:08 p.m. UTC | #5
> On Aug 23, 2024, at 11:03 AM, Olga Kornievskaia <aglo@umich.edu> wrote:
> 
> On Fri, Aug 23, 2024 at 10:44 AM Chuck Lever <chuck.lever@oracle.com> wrote:
>> 
>> On Fri, Aug 23, 2024 at 10:14:01AM -0400, Olga Kornievskaia wrote:
>>> states_show() relied on sc_type field to be of valid type
>>> before calling into a subfunction to show content of a
>>> particular stateid. But from commit 3f29cc82a84c we
>>> split the validity of the stateid into sc_status and no longer
>>> changed sc_type to 0 while unhashing the stateid. This
>>> resulted in kernel oopsing as something like
>>> nfs4_show_open() would derefence sc_file which was NULL.
>>> 
>>> To reproduce: mount the server with 4.0, read and close
>>> a file and then on the server cat /proc/fs/nfsd/clients/2/states
>>> 
>>> [  513.590804] Call trace:
>>> [  513.590925]  _raw_spin_lock+0xcc/0x160
>>> [  513.591119]  nfs4_show_open+0x78/0x2c0 [nfsd]
>>> [  513.591412]  states_show+0x44c/0x488 [nfsd]
>>> [  513.591681]  seq_read_iter+0x5d8/0x760
>>> [  513.591896]  seq_read+0x188/0x208
>>> [  513.592075]  vfs_read+0x148/0x470
>>> [  513.592241]  ksys_read+0xcc/0x178
>>> 
>>> Fixes: 3f29cc82a84c ("nfsd: split sc_status out of sc_type")
>>> Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
>>> ---
>>> fs/nfsd/nfs4state.c | 3 +++
>>> 1 file changed, 3 insertions(+)
>>> 
>>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>>> index c3def49074a4..8351724b8a43 100644
>>> --- a/fs/nfsd/nfs4state.c
>>> +++ b/fs/nfsd/nfs4state.c
>>> @@ -2907,6 +2907,9 @@ static int states_show(struct seq_file *s, void *v)
>>> {
>>>      struct nfs4_stid *st = v;
>>> 
>>> +     if (!st->sc_file)
>>> +             return 0;
>>> +
>>>      switch (st->sc_type) {
>>>      case SC_TYPE_OPEN:
>>>              return nfs4_show_open(s, st);
>>> --
>>> 2.43.5
>>> 
>> 
>> I'll wait for Neil/Jeff's Reviewed-by, but the root cause analysis
>> seems plausible to me, and I'll plan to apply it for v6.11-rc.
>> 
>> Btw, I noticed this at the tail of states_show():
>> 
>>        /* XXX: copy stateids? */
>> 
>> I'm not really sure, but those won't ever have an sc_file, will
>> they? Are COPY callback stateids something we want the server to
>> display in this code? Just musing aloud: maybe the NULL sc_file
>> check wants to be moved into the show helpers.
> 
> I can see that the copy stateids still have type NFS4_COPY_STID so
> they are not converted to the new type of SC_TYPE. But it just means
> we are not displaying them. I'm not sure what happens to sc_file for
> copy stateid, I'd need to check.

If you're already going to move the sc_file check into
nfs4_show_open(), you can defer looking at adding specific
support for callback stateids. We'll add it to the to-do
list.


--
Chuck Lever
Olga Kornievskaia Aug. 27, 2024, 6:46 p.m. UTC | #6
On Fri, Aug 23, 2024 at 11:10 AM Chuck Lever III <chuck.lever@oracle.com> wrote:
>
>
>
> > On Aug 23, 2024, at 11:03 AM, Olga Kornievskaia <aglo@umich.edu> wrote:
> >
> > On Fri, Aug 23, 2024 at 10:44 AM Chuck Lever <chuck.lever@oracle.com> wrote:
> >>
> >> On Fri, Aug 23, 2024 at 10:14:01AM -0400, Olga Kornievskaia wrote:
> >>> states_show() relied on sc_type field to be of valid type
> >>> before calling into a subfunction to show content of a
> >>> particular stateid. But from commit 3f29cc82a84c we
> >>> split the validity of the stateid into sc_status and no longer
> >>> changed sc_type to 0 while unhashing the stateid. This
> >>> resulted in kernel oopsing as something like
> >>> nfs4_show_open() would derefence sc_file which was NULL.
> >>>
> >>> To reproduce: mount the server with 4.0, read and close
> >>> a file and then on the server cat /proc/fs/nfsd/clients/2/states
> >>>
> >>> [  513.590804] Call trace:
> >>> [  513.590925]  _raw_spin_lock+0xcc/0x160
> >>> [  513.591119]  nfs4_show_open+0x78/0x2c0 [nfsd]
> >>> [  513.591412]  states_show+0x44c/0x488 [nfsd]
> >>> [  513.591681]  seq_read_iter+0x5d8/0x760
> >>> [  513.591896]  seq_read+0x188/0x208
> >>> [  513.592075]  vfs_read+0x148/0x470
> >>> [  513.592241]  ksys_read+0xcc/0x178
> >>>
> >>> Fixes: 3f29cc82a84c ("nfsd: split sc_status out of sc_type")
> >>> Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
> >>> ---
> >>> fs/nfsd/nfs4state.c | 3 +++
> >>> 1 file changed, 3 insertions(+)
> >>>
> >>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> >>> index c3def49074a4..8351724b8a43 100644
> >>> --- a/fs/nfsd/nfs4state.c
> >>> +++ b/fs/nfsd/nfs4state.c
> >>> @@ -2907,6 +2907,9 @@ static int states_show(struct seq_file *s, void *v)
> >>> {
> >>>      struct nfs4_stid *st = v;
> >>>
> >>> +     if (!st->sc_file)
> >>> +             return 0;
> >>> +
> >>>      switch (st->sc_type) {
> >>>      case SC_TYPE_OPEN:
> >>>              return nfs4_show_open(s, st);
> >>> --
> >>> 2.43.5
> >>>
> >>
> >> I'll wait for Neil/Jeff's Reviewed-by, but the root cause analysis
> >> seems plausible to me, and I'll plan to apply it for v6.11-rc.
> >>
> >> Btw, I noticed this at the tail of states_show():
> >>
> >>        /* XXX: copy stateids? */
> >>
> >> I'm not really sure, but those won't ever have an sc_file, will
> >> they? Are COPY callback stateids something we want the server to
> >> display in this code? Just musing aloud: maybe the NULL sc_file
> >> check wants to be moved into the show helpers.
> >
> > I can see that the copy stateids still have type NFS4_COPY_STID so
> > they are not converted to the new type of SC_TYPE. But it just means
> > we are not displaying them. I'm not sure what happens to sc_file for
> > copy stateid, I'd need to check.
>
> If you're already going to move the sc_file check into
> nfs4_show_open(), you can defer looking at adding specific
> support for callback stateids. We'll add it to the to-do
> list.

Now that I've looked at some copy code and also got more familiar with
this walking the stateids in proc, I'd like to note that proc only
walks the stateids that are store in clp->cl_stateids but the copy
stateid that we keep around (and those are the copy stateids in the
source server) are stored under the nfsd_net (namespace). Not to say
we shouldn't modify states_show() not to add walking a different list
but wanted to raise it. Also on the destination server, we stop async
copy stateid under the clp->async_copies list and they only live for
the lifetime of the copy. I know this bordes on a different discussion
of keeping copy stateids...

>
>
> --
> Chuck Lever
>
>
diff mbox series

Patch

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index c3def49074a4..8351724b8a43 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2907,6 +2907,9 @@  static int states_show(struct seq_file *s, void *v)
 {
 	struct nfs4_stid *st = v;
 
+	if (!st->sc_file)
+		return 0;
+
 	switch (st->sc_type) {
 	case SC_TYPE_OPEN:
 		return nfs4_show_open(s, st);