On 2019-09-05, Peter Zijlstra wrote: > On Thu, Sep 05, 2019 at 11:43:05AM +0200, Peter Zijlstra wrote: > > On Thu, Sep 05, 2019 at 07:26:22PM +1000, Aleksa Sarai wrote: > > > On 2019-09-05, Peter Zijlstra wrote: > > > > On Thu, Sep 05, 2019 at 06:19:22AM +1000, Aleksa Sarai wrote: > > > > > +/** > > > > > + * copy_struct_to_user: copy a struct to user space > > > > > + * @dst: Destination address, in user space. > > > > > + * @usize: Size of @dst struct. > > > > > + * @src: Source address, in kernel space. > > > > > + * @ksize: Size of @src struct. > > > > > + * > > > > > + * Copies a struct from kernel space to user space, in a way that guarantees > > > > > + * backwards-compatibility for struct syscall arguments (as long as future > > > > > + * struct extensions are made such that all new fields are *appended* to the > > > > > + * old struct, and zeroed-out new fields have the same meaning as the old > > > > > + * struct). > > > > > + * > > > > > + * @ksize is just sizeof(*dst), and @usize should've been passed by user space. > > > > > + * The recommended usage is something like the following: > > > > > + * > > > > > + * SYSCALL_DEFINE2(foobar, struct foo __user *, uarg, size_t, usize) > > > > > + * { > > > > > + * int err; > > > > > + * struct foo karg = {}; > > > > > + * > > > > > + * // do something with karg > > > > > + * > > > > > + * err = copy_struct_to_user(uarg, usize, &karg, sizeof(karg)); > > > > > + * if (err) > > > > > + * return err; > > > > > + * > > > > > + * // ... > > > > > + * } > > > > > + * > > > > > + * There are three cases to consider: > > > > > + * * If @usize == @ksize, then it's copied verbatim. > > > > > + * * If @usize < @ksize, then kernel space is "returning" a newer struct to an > > > > > + * older user space. In order to avoid user space getting incomplete > > > > > + * information (new fields might be important), all trailing bytes in @src > > > > > + * (@ksize - @usize) must be zerored > > > > > > > > s/zerored/zero/, right? > > > > > > It should've been "zeroed". > > > > That reads wrong to me; that way it reads like this function must take > > that action and zero out the 'rest'; which is just wrong. > > > > This function must verify those bytes are zero, not make them zero. > > > > > > > , otherwise -EFBIG is returned. > > > > > > > > 'Funny' that, copy_struct_from_user() below seems to use E2BIG. > > > > > > This is a copy of the semantics that sched_[sg]etattr(2) uses -- E2BIG for > > > a "too big" struct passed to the kernel, and EFBIG for a "too big" > > > struct passed to user-space. I would personally have preferred EMSGSIZE > > > instead of EFBIG, but felt using the existing error codes would be less > > > confusing. > > > > Sadly a recent commit: > > > > 1251201c0d34 ("sched/core: Fix uclamp ABI bug, clean up and robustify sched_read_attr() ABI logic and code") > > > > Made the situation even 'worse'. > > And thinking more about things; I'm not convinced the above patch is > actually right. > > Do we really want to simply truncate all the attributes of the task? > > And should we not at least set sched_flags when there are non-default > clamp values applied? > > See; that is I think the primary bug that had chrt failing; we tried to > publish the default clamp values as !0. I just saw this patch in -rc8 -- should I even attempt to port sched_getattr(2) to copy_struct_to_user()? I agree that publishing a default non-zero value is a mistake -- once you do that, old user space will either get confused or lose information. -- Aleksa Sarai Senior Software Engineer (Containers) SUSE Linux GmbH