Re: [PATCH] sched/headers: Fix sched_setattr userspace compilation breakage

From: Linus Torvalds
Date: Thu May 28 2020 - 19:23:54 EST


On Thu, May 28, 2020 at 4:09 PM Joel Fernandes <joel@xxxxxxxxxxxxxxxxx> wrote:
>
> > So no, this patch is fundamentally wrong. It negates the whole point
> > of having a uapi header at all.
>
> Sorry, I naively assumed that headers in 'include/uapi/' are safe to include
> from userspace. I feel terrible.

Well, they "kind of" are safe to include.

It's just that normally they are meant for system integrators to
include as part of the system header files. So they are designed not
to be safe for normal programs, but for library writers.

And to make things more confusing, sometimes people _do_ include
kernel header files directly, just because they want to get features
that either haven't been exposed by the system libraries, or because
the system libraries copied the uapi header files for an older version
of the kernel, and you want the shiny new feature, so...

And some of those header files are easier to do that with than others...

> The problem is <sched.h> still does not get us 'struct sched_attr' even
> though the manpage of sched_setattr(2) says including <sched.h> is all that's
> needed.

Ouch. But clearly you get it from -somewhere- since it then complains
about the double declaration.

Strange.

> Also, even if glibc included 'include/uapi/linux/sched/types.h' to get struct
> sched_attr's definition, we would run into the same issue I reported right?
> The 'struct sched_param' is already defined by glibc, and this header
> redefines it.

That's kind of the point: glibc sets up whatever system headers it
wants. The uapi ones are there to _help_ it, but it's not like glibc
_has_ to use them.

In fact, traditionally we didn't have any uapi header files at all,
and we just expected the system libraries to scrape them and make
their own private copies.

The uapi headers are _meant_ to make that easier, and to allow system
headers to then co-exists with the inevitable "I need to get newer
headers because I'm using a bleeding edge feature that glibc isn't
exposing" crowd.

Put another way: a very non-portable programs _could_ include the uapi
headers directly, if the system library headers were set up that way.

More commonly, what bleeding edge people do when the system header
files don't play nice, is to just build their very own libraries and
copy the bleeding-edge features directly from the kernel. So you'll
find things like

#ifndef __NR_clone3
#define __NR_clone3 435
#endif

syscall(__NR_clone3, ...);

in user space that wants to use the clone3 system call, but knows that
it hasn't made it into the glibc headers yet, so the program just
forced the local knowledge of it.

That's obviously generally easier to do with macro defines like the
above, exactly because you can trivially _test_ whether they've been
exposed or not.

So yes, this is a horrid mess.

But the *intent* is that the uapi header files should be things that
system library implementations can just use directly, and then the
"special" users could mix-and-match if everything is wonderful.

Which it seldom is.

But that's why putting those interface declarations inside a #ifdef
__KERNEL__ would completely destroy the whole point.

Linus