On Wed, Aug 28, 2019 at 02:06:50PM +0200, David Sterba wrote:
> On Thu, Aug 15, 2019 at 02:04:06PM -0700, Omar Sandoval wrote:
> >  #define BTRFS_IOC_SEND_32 _IOW(BTRFS_IOCTL_MAGIC, 38, \
> >                            struct btrfs_ioctl_send_args_32)
> > +
> > +struct btrfs_ioctl_compressed_pwrite_args_32 {
> > +   __u64 offset;           /* in */
> > +   __u32 compressed_len;   /* in */
> > +   __u32 orig_len;         /* in */
> > +   __u32 compress_type;    /* in */
> > +   __u32 reserved[9];
> > +   compat_uptr_t buf;      /* in */
> > +} __attribute__ ((__packed__));
> > +
> > +#define BTRFS_IOC_COMPRESSED_PWRITE_32 _IOW(BTRFS_IOCTL_MAGIC, 63, \
> > +                            struct btrfs_ioctl_compressed_pwrite_args_32)
> 
> Note that the _32 is a workaround for a mistake in the send ioctl
> definitions that slipped trhough. Any pointer in the structure changes
> the ioctl number on 32bit and 64bit.
> 
> But as the raw data ioctl is new there's point to copy the mistake. The
> alignment and width can be forced eg. like
> 
> > +   void __user *buf;       /* in */
> 
>       union {
>               void __user *buf;
>               __u64 __buf_alignment;
>       };
> 
> This allows to user buf as a buffer without casts to a intermediate
> type.

I don't think this works on big-endian architectures. Let's say a 32-bit
application does:

struct btrfs_ioctl_compressed_pwrite_args_32 {
        .buf = 0x12345678,
};

The pointer will be in the first 4 bytes of the 8-byte union:

0    1    2    3    4    5    6    7
0x12 0x34 0x56 0x78 0x00 0x00 0x00 0x00

But, the 64-bit kernel will read buf as 0x1234567800000000. Let me know
if I messed up my analysis, but I think we need the compat stuff.

Reply via email to