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.