All of lore.kernel.org
 help / color / mirror / Atom feed
* [bug report] ovl: make sure that real fid is 32bit aligned in memory
@ 2019-12-13 10:37 Dan Carpenter
  2019-12-13 12:22 ` Miklos Szeredi
  0 siblings, 1 reply; 6+ messages in thread
From: Dan Carpenter @ 2019-12-13 10:37 UTC (permalink / raw)
  To: amir73il; +Cc: linux-unionfs

Hello Amir Goldstein,

This is a semi-automatic email about new static checker warnings.

The patch cbe7fba8edfc: "ovl: make sure that real fid is 32bit 
aligned in memory" from Nov 15, 2019, leads to the following Smatch 
complaint:

    fs/overlayfs/copy_up.c:338 ovl_set_origin()
     warn: variable dereferenced before check 'fh' (see line 337)

fs/overlayfs/copy_up.c
   336		 */
   337		err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh->buf,
                                                                          ^^^^^^^
The patch adds an unconditional dereference

   338					 fh ? fh->fb.len : 0, 0);
                                         ^^
but "fh" can be NULL.

   339		kfree(fh);
   340	

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [bug report] ovl: make sure that real fid is 32bit aligned in memory
  2019-12-13 10:37 [bug report] ovl: make sure that real fid is 32bit aligned in memory Dan Carpenter
@ 2019-12-13 12:22 ` Miklos Szeredi
  2019-12-13 12:58   ` Dan Carpenter
  0 siblings, 1 reply; 6+ messages in thread
From: Miklos Szeredi @ 2019-12-13 12:22 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: Amir Goldstein, overlayfs

On Fri, Dec 13, 2019 at 11:38 AM Dan Carpenter <dan.carpenter@oracle.com> wrote:
>
> Hello Amir Goldstein,
>
> This is a semi-automatic email about new static checker warnings.
>
> The patch cbe7fba8edfc: "ovl: make sure that real fid is 32bit
> aligned in memory" from Nov 15, 2019, leads to the following Smatch
> complaint:
>
>     fs/overlayfs/copy_up.c:338 ovl_set_origin()
>      warn: variable dereferenced before check 'fh' (see line 337)
>
> fs/overlayfs/copy_up.c
>    336           */
>    337          err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh->buf,
>                                                                           ^^^^^^^
> The patch adds an unconditional dereference

But in fact fh->buf is not a dereference:

struct ovl_fh {
    u8 padding[3];    /* make sure fb.fid is 32bit aligned */
    union {
        struct ovl_fb fb;
        u8 buf[0];
    };
} __packed;

Subsequent code will also not dereference fh->buf, because the
supplied size is zero.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [bug report] ovl: make sure that real fid is 32bit aligned in memory
  2019-12-13 12:22 ` Miklos Szeredi
@ 2019-12-13 12:58   ` Dan Carpenter
  0 siblings, 0 replies; 6+ messages in thread
From: Dan Carpenter @ 2019-12-13 12:58 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Amir Goldstein, overlayfs

On Fri, Dec 13, 2019 at 01:22:10PM +0100, Miklos Szeredi wrote:
> On Fri, Dec 13, 2019 at 11:38 AM Dan Carpenter <dan.carpenter@oracle.com> wrote:
> >
> > Hello Amir Goldstein,
> >
> > This is a semi-automatic email about new static checker warnings.
> >
> > The patch cbe7fba8edfc: "ovl: make sure that real fid is 32bit
> > aligned in memory" from Nov 15, 2019, leads to the following Smatch
> > complaint:
> >
> >     fs/overlayfs/copy_up.c:338 ovl_set_origin()
> >      warn: variable dereferenced before check 'fh' (see line 337)
> >
> > fs/overlayfs/copy_up.c
> >    336           */
> >    337          err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh->buf,
> >                                                                           ^^^^^^^
> > The patch adds an unconditional dereference
> 
> But in fact fh->buf is not a dereference:
> 
> struct ovl_fh {
>     u8 padding[3];    /* make sure fb.fid is 32bit aligned */
>     union {
>         struct ovl_fb fb;
>         u8 buf[0];
>     };
> } __packed;
> 
> Subsequent code will also not dereference fh->buf, because the
> supplied size is zero.

Ah yes.  Thanks.  Smatch got confused because the array is inside a
union.  Sorry.

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [bug report] ovl: make sure that real fid is 32bit aligned in memory
  2020-05-05 16:13 ` Amir Goldstein
@ 2020-05-05 18:08   ` Dan Carpenter
  0 siblings, 0 replies; 6+ messages in thread
From: Dan Carpenter @ 2020-05-05 18:08 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: overlayfs

On Tue, May 05, 2020 at 07:13:20PM +0300, Amir Goldstein wrote:
> > The patch cbe7fba8edfc: "ovl: make sure that real fid is 32bit
> > aligned in memory" from Nov 15, 2019, leads to the following static
> > checker warning:
> >
> >         fs/overlayfs/export.c:791 ovl_fid_to_fh()
> >         warn: check that subtract can't underflow
> >
> > fs/overlayfs/export.c
> >    775  static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type)
> >    776  {
> >    777          struct ovl_fh *fh;
> >    778
> >    779          /* If on-wire inner fid is aligned - nothing to do */
> >    780          if (fh_type == OVL_FILEID_V1)
> >    781                  return (struct ovl_fh *)fid;
> >    782
> >    783          if (fh_type != OVL_FILEID_V0)
> >    784                  return ERR_PTR(-EINVAL);
> >    785
> >    786          fh = kzalloc(buflen, GFP_KERNEL);
> 
> Doesn't Smatch warn on possible kmalloc(0)?
> That can't be good. Right?

No, no.  Allocating zero bytes is a useful feature.

	size = 0;
	buf = kzalloc(size, GFP_KERNEL);

	for (i = 0; i < size; i++)
		buf[i] = 42;
	memcpy(dest, buf, size);
	copy_to_user(p, dest, size);

That all works.  Neat, huh?

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [bug report] ovl: make sure that real fid is 32bit aligned in memory
  2020-05-05 13:50 Dan Carpenter
@ 2020-05-05 16:13 ` Amir Goldstein
  2020-05-05 18:08   ` Dan Carpenter
  0 siblings, 1 reply; 6+ messages in thread
From: Amir Goldstein @ 2020-05-05 16:13 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: overlayfs

On Tue, May 5, 2020 at 4:50 PM Dan Carpenter <dan.carpenter@oracle.com> wrote:
>
> Hello Amir Goldstein,

Hi Dan,

>
> The patch cbe7fba8edfc: "ovl: make sure that real fid is 32bit
> aligned in memory" from Nov 15, 2019, leads to the following static
> checker warning:
>
>         fs/overlayfs/export.c:791 ovl_fid_to_fh()
>         warn: check that subtract can't underflow
>
> fs/overlayfs/export.c
>    775  static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type)
>    776  {
>    777          struct ovl_fh *fh;
>    778
>    779          /* If on-wire inner fid is aligned - nothing to do */
>    780          if (fh_type == OVL_FILEID_V1)
>    781                  return (struct ovl_fh *)fid;
>    782
>    783          if (fh_type != OVL_FILEID_V0)
>    784                  return ERR_PTR(-EINVAL);
>    785
>    786          fh = kzalloc(buflen, GFP_KERNEL);

Doesn't Smatch warn on possible kmalloc(0)?
That can't be good. Right?

>    787          if (!fh)
>    788                  return ERR_PTR(-ENOMEM);
>    789
>    790          /* Copy unaligned inner fh into aligned buffer */
>    791          memcpy(&fh->fb, fid, buflen - OVL_FH_WIRE_OFFSET);
>                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
>    792          return fh;
>    793  }
>
> Samtch thinks buflen can be "0,4-128".  OVL_FH_WIRE_OFFSET is 3. The
> problem is that 0 - 3 is a negative and the memcpy() will crash.
>
> In do_handle_to_path() we do:
>
>         handle_dwords = handle->handle_bytes >> 2;
>
> Handle ->handle_bytes is non-zero but when it's >> 2 then it can become
> zero.  It's a round down.  In ovl_fh_to_dentry() we do:
>
>         int len = fh_len << 2;
>
> If we rounded down to zero then "len" is still zero.

I agree with your analysis.
The reproducer should be trivial because there are no sanotify
checks prior to buggy code except for fh_type != OVL_FILEID_V0.

> Obviously one fix
> would be to add a check in ovl_fid_to_fh().
>
>         if (buflen < sizeof(*fh))
>                 return ERR_PTR(-EINVAL);

Correct fix IMO in the context of ovl_fid_to_fh() should be:

if (buflen <= OVL_FH_WIRE_OFFSET)
                 return ERR_PTR(-EINVAL);

Just to avoid the crash.

>
> But that feels like papering over the bug.
>

It won't be papering over, because of the check:
        err = ovl_check_fh_len(fh, len);

This was the check before the offending commit that was responsible
for sanity checking the value of len, but the commit slipped in this
code before the sanity check.

I assume you will be sending the patch.
I will put writing a test on my TODO.

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [bug report] ovl: make sure that real fid is 32bit aligned in memory
@ 2020-05-05 13:50 Dan Carpenter
  2020-05-05 16:13 ` Amir Goldstein
  0 siblings, 1 reply; 6+ messages in thread
From: Dan Carpenter @ 2020-05-05 13:50 UTC (permalink / raw)
  To: amir73il; +Cc: linux-unionfs

Hello Amir Goldstein,

The patch cbe7fba8edfc: "ovl: make sure that real fid is 32bit
aligned in memory" from Nov 15, 2019, leads to the following static
checker warning:

	fs/overlayfs/export.c:791 ovl_fid_to_fh()
	warn: check that subtract can't underflow

fs/overlayfs/export.c
   775  static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type)
   776  {
   777          struct ovl_fh *fh;
   778  
   779          /* If on-wire inner fid is aligned - nothing to do */
   780          if (fh_type == OVL_FILEID_V1)
   781                  return (struct ovl_fh *)fid;
   782  
   783          if (fh_type != OVL_FILEID_V0)
   784                  return ERR_PTR(-EINVAL);
   785  
   786          fh = kzalloc(buflen, GFP_KERNEL);
   787          if (!fh)
   788                  return ERR_PTR(-ENOMEM);
   789  
   790          /* Copy unaligned inner fh into aligned buffer */
   791          memcpy(&fh->fb, fid, buflen - OVL_FH_WIRE_OFFSET);
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^

   792          return fh;
   793  }

Samtch thinks buflen can be "0,4-128".  OVL_FH_WIRE_OFFSET is 3. The
problem is that 0 - 3 is a negative and the memcpy() will crash.

In do_handle_to_path() we do:

	handle_dwords = handle->handle_bytes >> 2;

Handle ->handle_bytes is non-zero but when it's >> 2 then it can become
zero.  It's a round down.  In ovl_fh_to_dentry() we do:

	int len = fh_len << 2;

If we rounded down to zero then "len" is still zero.  Obviously one fix
would be to add a check in ovl_fid_to_fh().

	if (buflen < sizeof(*fh))
		return ERR_PTR(-EINVAL);

But that feels like papering over the bug.

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-05-05 18:08 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-13 10:37 [bug report] ovl: make sure that real fid is 32bit aligned in memory Dan Carpenter
2019-12-13 12:22 ` Miklos Szeredi
2019-12-13 12:58   ` Dan Carpenter
2020-05-05 13:50 Dan Carpenter
2020-05-05 16:13 ` Amir Goldstein
2020-05-05 18:08   ` Dan Carpenter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.