On Mon, May 09, 2022 at 05:02:13PM +0200, Michal Privoznik wrote: > Since its 5.14 release the Linux kernel allows userspace to > define trusted groups of processes/threads that can run on > sibling Hyper Threads (HT) at the same time. This is to mitigate > side channel attacks like L1TF or MDS. If there are no tasks to > fully utilize all HTs, then a HT will idle instead of running a > task from another (un-)trusted group. > > On low level, this is implemented by cookies (effectively an UL > value): processes in the same trusted group share the same cookie > and cookie is unique to the group. There are four basic > operations: > > 1) PR_SCHED_CORE_GET -- get cookie of given PID, > 2) PR_SCHED_CORE_CREATE -- create a new unique cookie for PID, > 3) PR_SCHED_CORE_SHARE_TO -- push cookie of the caller onto > another PID, > 4) PR_SCHED_CORE_SHARE_FROM -- pull cookie of another PID into > the caller. > > Since a system where the code is built can be different to the > one where the code is ran let's provide declaration of some > values. It's not unusual for distros to ship older linux-headers > than the actual kernel. > > Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> > --- > src/libvirt_private.syms | 4 ++ > src/util/virprocess.c | 124 +++++++++++++++++++++++++++++++++++++++ > src/util/virprocess.h | 8 +++ > 3 files changed, 136 insertions(+) Reviewed-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> > diff --git a/src/util/virprocess.c b/src/util/virprocess.c > index 36d7df050a..cd4f3fc7e7 100644 > --- a/src/util/virprocess.c > +++ b/src/util/virprocess.c > @@ -57,6 +57,10 @@ > # include <windows.h> > #endif > > +#if WITH_CAPNG This feels odd - what relation has CAPNG got with prctl ? > +# include <sys/prctl.h> > +#endif > + > #include "virprocess.h" > #include "virerror.h" > #include "viralloc.h" > @@ -1906,3 +1910,123 @@ virProcessGetSchedInfo(unsigned long long *cpuWait, > return 0; > } > #endif /* __linux__ */ > + > +#ifdef __linux__ > +# ifndef PR_SCHED_CORE > +/* Copied from linux/prctl.h */ > +# define PR_SCHED_CORE 62 > +# define PR_SCHED_CORE_GET 0 > +# define PR_SCHED_CORE_CREATE 1 /* create unique core_sched cookie */ > +# define PR_SCHED_CORE_SHARE_TO 2 /* push core_sched cookie to pid */ > +# define PR_SCHED_CORE_SHARE_FROM 3 /* pull core_sched cookie to pid */ > +# endif > + > +/* Unfortunately, kernel-headers forgot to export these. */ > +# ifndef PR_SCHED_CORE_SCOPE_THREAD > +# define PR_SCHED_CORE_SCOPE_THREAD 0 > +# define PR_SCHED_CORE_SCOPE_THREAD_GROUP 1 > +# define PR_SCHED_CORE_SCOPE_PROCESS_GROUP 2 > +# endif > + > +/** > + * virProcessSchedCoreAvailable: > + * > + * Check whether kernel supports Core Scheduling (CONFIG_SCHED_CORE), i.e. only > + * a defined set of PIDs/TIDs can run on sibling Hyper Threads at the same > + * time. > + * > + * Returns: 1 if Core Scheduling is available, > + * 0 if Core Scheduling is NOT available, > + * -1 otherwise. > + */ > +int > +virProcessSchedCoreAvailable(void) > +{ > + unsigned long cookie = 0; > + int rc; > + > + /* Let's just see if we can get our own sched cookie, and if yes we can > + * safely assume CONFIG_SCHED_CORE kernel is available. */ > + rc = prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET, 0, > + PR_SCHED_CORE_SCOPE_THREAD, &cookie); > + > + return rc == 0 ? 1 : errno == EINVAL ? 0 : -1; > +} > + > +/** > + * virProcessSchedCoreCreate: > + * > + * Creates a new trusted group for the caller process. > + * > + * Returns: 0 on success, > + * -1 otherwise, with errno set. > + */ > +int > +virProcessSchedCoreCreate(void) > +{ > + /* pid = 0 (3rd argument) means the calling process. */ > + return prctl(PR_SCHED_CORE, PR_SCHED_CORE_CREATE, 0, > + PR_SCHED_CORE_SCOPE_THREAD_GROUP, 0); > +} > + > +/** > + * virProcessSchedCoreShareFrom: > + * @pid: PID to share group with > + * > + * Places the current caller process into the trusted group of @pid. > + * > + * Returns: 0 on success, > + * -1 otherwise, with errno set. > + */ > +int > +virProcessSchedCoreShareFrom(pid_t pid) > +{ > + return prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_FROM, pid, > + PR_SCHED_CORE_SCOPE_THREAD, 0); > +} > + > +/** > + * virProcessSchedCoreShareTo: > + * @pid: PID to share group with > + * > + * Places foreign @pid into the trusted group of the current caller process. > + * > + * Returns: 0 on success, > + * -1 otherwise, with errno set. > + */ > +int > +virProcessSchedCoreShareTo(pid_t pid) > +{ > + return prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_TO, pid, > + PR_SCHED_CORE_SCOPE_THREAD, 0); > +} > + > +#else /* !__linux__ */ > + > +int > +virProcessSchedCoreAvailable(void) > +{ > + return 0; > +} > + > +int > +virProcessSchedCoreCreate(void) > +{ > + errno = ENOSYS; > + return -1; > +} > + > +int > +virProcessSchedCoreShareFrom(pid_t pid G_GNUC_UNUSED) > +{ > + errno = ENOSYS; > + return -1; > +} > + > +int > +virProcessSchedCoreShareTo(pid_t pid G_GNUC_UNUSED) > +{ > + errno = ENOSYS; > + return -1; > +} > +#endif /* !__linux__ */ > diff --git a/src/util/virprocess.h b/src/util/virprocess.h > index 086fbe0e4d..e01f9a24ee 100644 > --- a/src/util/virprocess.h > +++ b/src/util/virprocess.h > @@ -202,3 +202,11 @@ int virProcessGetStatInfo(unsigned long long *cpuTime, > int virProcessGetSchedInfo(unsigned long long *cpuWait, > pid_t pid, > pid_t tid); > + > +int virProcessSchedCoreAvailable(void); > + > +int virProcessSchedCoreCreate(void); > + > +int virProcessSchedCoreShareFrom(pid_t pid); > + > +int virProcessSchedCoreShareTo(pid_t pid); > -- > 2.35.1 > With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|