Re: reproducible hard lock with lxrt + sys_setresuid -- does it happen in current RTAI?
Paolo Mantegazza <[email protected]> Thu, 20 Apr 2017 11:15:01 +0200
| Newsgroups | gmane.linux.real-time.rtai |
|---|---|
| Message-ID | <[email protected]> |
I'm little surprised of such a hard lock.
It is not a matter of RTAI version. It just violates the basics of the
dual kernel approach subtended to RTAI-LXRT.
I assume that to change the effective uid of a running task Linux has to
somewhat operate on it.
Well, if it is so, if not then I'm wrong, it takes a task that sees
sleeping and changes something beneath it.
Unfortunately that task is not its and is lively running under "another
kernel".
Thus, what will happen?
Therefore, before doing that, some cooperation is needed and you have
to give back any involved hard real time task to linux.
Out of the many, three possible ways are attached. The messaging type,
could be structured also with automatic replies through proxies (Pierre
Cloutier).
Paolo
On 04/20/2017 03:51 AM, Jeff Epler wrote:
> In at least some older versions of rtai lxrt, calling seteuid() while a RT
> task exists in the same process causes a hard lock. This is reproducible on
> a kernel and rtai version shipped by linuxcnc.org, but I don't know about
> current ones.
>
> Can someone tell me if this is still reproducing with current RTAI
> and kernel trees so I know whether to continue barking up this tree,
> or whether it's specific to versions so old that only linuxcnc uses
> them anymore?
>
> Compile the below code with e.g.,
> $ g++ -std=c++14 threadtest.cc -I /usr/include/rtai -pthread -llxrt
> If you don't want to hard-lock your system, you will need to
> -DNO_KABOOM, which just skips the calls to seteuid().
>
> Remember to manually insert (insmod / modprobe / whatever) the
> necessary modules, such as rtai_hal and rtai_sched, dependent on
> your setup.
>
> Then, run with
> $ sudo ./a.out
> The program calls sync() first thing so hopefully you won't lose much data
> if it succeeds in hard locking you.
>
> If it hard locks your computer, yay, you've reproduced my bug report.
>
> If the 'final value' is 0 then the RT code never ran at all (non
> root, or modules not loaded?).
>
> If it's large (say, a few million) then probably the task ran but
> didn't enter real-time periodic mode (not root, or modules not
> loaded?)
>
> If it's around 10,000 then congratulations: you may not have the bug!
>
> tested (and fails consistently) on
> 3.18.0-1-rtai-amd64 #1 SMP PREEMPT Debian 3.18.20-1linuxcnc (2016-06-22) x86_64 GNU/Linux
> with rtai 5.0~test2.2016.05.12.37.g1d358aa from seb's git except we
> rebased it or something so that ref doesn't seem to exist anymore :(
> It's probably similar to our ref a844a0751b11f.
>
> Kconfig file at
> https://emergent.unpythonic.net/files/sandbox/config-3.18.0-1-rtai-amd64
>
> rtai tree including build system in debian/ at
> https://github.com/SebKuzminsky/rtai (see branch vulcano-debs;
> debian/rules.in shows configure flags)
>
> My unsubstantiated theory is that sys_setresuid (which is what glibc
> seteuid calls) probably has to do something for each task in the
> process to make it take the new credentials, but this can deadlock
> when the other task is hard realtime.
>
> Jeff
>
> //- cut here for the reproducer program "threadtest.cc" ----------------
> #include <atomic>
> #include <iterator>
> #include <pthread.h>
> #include <stdio.h>
>
> #pragma GCC diagnostic push
> #pragma GCC diagnostic ignored "-Wnarrowing"
> #pragma GCC diagnostic ignored "-Wvla"
> #include <rtai_lxrt.h>
> #pragma GCC diagnostic pop
>
> namespace
> {
>
> constexpr long period = 100'000; // 100us
> constexpr int policy = SCHED_FIFO;
> int prio = sched_get_priority_max(policy);
> std::atomic<bool> stop;
> std::atomic<int> count;
> pthread_t thr;
>
> void *wrapper(__attribute__((unused)) void *arg) {
> int nprocs = sysconf( _SC_NPROCESSORS_ONLN );
> auto rt_task = rt_task_init_schmod(1, 0, 0, 0, SCHED_FIFO,
> 1u << (nprocs - 1));
> rt_set_periodic_mode();
>
> rt_make_hard_real_time();
> rt_task_make_periodic_relative_ns(rt_task, period, period);
>
> while(!stop) { count++; rt_task_wait_period(); }
>
> return nullptr;
> }
> }
>
> int main() {
> sync();
> printf("initial value: %d\n", count.load());
> if(pthread_create(&thr, nullptr, &wrapper, nullptr) < 0) {
> perror("pthred_create");
> abort();
> }
>
> for(int i=0; i<1000; i++) {
> usleep(1000);
> #ifndef NO_KABOOM
> seteuid(1000);
> seteuid(0);
> #endif
> }
>
> stop = true;
>
> pthread_join(thr, nullptr);
>
> printf("final value: %d\n", count.load());
> }
>
> _______________________________________________
> Rtai mailing list
> [email protected]
> https://mail.rtai.org/cgi-bin/mailman/listinfo/rtai
_______________________________________________
Rtai mailing list
[email protected]
https://mail.rtai.org/cgi-bin/mailman/listinfo/rtai
test1.c
(text/x-csrc, 1.1 KB)
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <rtai_lxrt.h>
#define KABOOM
long period = 100000; // ns
int policy = SCHED_FIFO;
int stop;
int count;
int makesoft;
pthread_t thr;
void *wrapper(void *arg) {
int nprocs = sysconf( _SC_NPROCESSORS_ONLN );
RT_TASK *rt_task = rt_task_init_schmod(1, 0, 0, 0, SCHED_FIFO, 1u << (nprocs - 1));
rt_set_periodic_mode();
rt_make_hard_real_time();
rt_task_make_periodic_relative_ns(rt_task, period, period);
while(!stop) {
count++;
rt_task_wait_period();
if (makesoft > 0) {
rt_make_soft_real_time();
makesoft = 0;
} else if (makesoft < 0) {
rt_make_hard_real_time();
makesoft = 0;
}
}
rt_make_soft_real_time();
return NULL;
}
int main(void)
{
sync();
printf("initial value: %d\n", count);
if(pthread_create(&thr, NULL, &wrapper, NULL) < 0) {
perror("pthred_create");
abort();
}
for(int i = 0; i < 1000; i++) {
usleep(1000);
#ifdef KABOOM
makesoft = 1;
while (makesoft);
seteuid(1000);
seteuid(0);
makesoft = -1;
while (makesoft);
#endif
}
stop = 1;
pthread_join(thr, NULL);
printf("final value: %d\n", count);
}
test2.c
(text/x-csrc, 1 KB)
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <rtai_lxrt.h>
#define KABOOM
long period = 100000; // ns
int policy = SCHED_FIFO;
int stop;
int count;
int changeuid;
pthread_t thr;
void *wrapper(void *arg) {
int nprocs = sysconf( _SC_NPROCESSORS_ONLN );
RT_TASK *rt_task = rt_task_init_schmod(1, 0, 0, 0, SCHED_FIFO, 1u << (nprocs - 1));
rt_set_periodic_mode();
rt_make_hard_real_time();
rt_task_make_periodic_relative_ns(rt_task, period, period);
while(!stop) {
count++;
rt_task_wait_period();
if (changeuid > 0) {
seteuid(1000);
seteuid(0);
changeuid = 0;
}
}
rt_make_soft_real_time();
return NULL;
}
int main(void)
{
sync();
printf("initial value: %d\n", count);
if(pthread_create(&thr, NULL, &wrapper, NULL) < 0) {
perror("pthred_create");
abort();
}
for(int i = 0; i < 1000; i++) {
usleep(1000);
#ifdef KABOOM
changeuid = 1;
while (changeuid);
#endif
}
stop = 1;
pthread_join(thr, NULL);
printf("final value: %d\n", count);
}
test3.c
(text/x-csrc, 1.2 KB)
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <rtai_lxrt.h>
#include <rtai_msg.h>
#define KABOOM
long period = 100000; // ns
int policy = SCHED_FIFO;
int stop;
int count;
int changeuid;
pthread_t thr;
RT_TASK *rt_task;
void *wrapper(void *arg)
{
unsigned long msg;
int nprocs = sysconf( _SC_NPROCESSORS_ONLN );
RT_TASK *rpc_task;
rt_task = rt_task_init_schmod(1, 0, 0, 0, SCHED_FIFO, 1u << (nprocs - 1));
rt_set_periodic_mode();
rt_make_hard_real_time();
rt_task_make_periodic_relative_ns(rt_task, period, period);
while(!stop) {
count++;
rt_task_wait_period();
if ((rpc_task = rt_receive_if(NULL, &msg)) != NULL) {
seteuid(msg);
rt_return(rpc_task, 0);
}
}
rt_make_soft_real_time();
return NULL;
}
int main(void)
{
unsigned long rep;
sync();
printf("initial value: %d\n", count);
if(pthread_create(&thr, NULL, &wrapper, NULL) < 0) {
perror("pthred_create");
abort();
}
rt_task_init_schmod(2, 0, 0, 0, SCHED_FIFO, 0xF);
for(int i = 0; i < 1000; i++) {
usleep(1000);
#ifdef KABOOM
rt_rpc(rt_task, 1000, &rep);
rt_rpc(rt_task, 0, &rep);
#endif
}
stop = 1;
pthread_join(thr, NULL);
printf("final value: %d\n", count);
}