/* DF-2794: sys_lwp_rtprio() with tid == -1 ignores the target pid and
 * always operates on the caller's own lwp.
 *
 * Run as root: fork a child; RTP_SET(pid=child, tid=-1, prio).
 * expect (vulnerable): set succeeds; the CALLER's rtprio changed to
 *   what was intended for the child, the child's rtprio unchanged.
 * expect (patched): the CHILD's first lwp gets the rtprio; caller unchanged.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/rtprio.h>
#include <sys/types.h>

/* libc provides lwp_rtprio(3): int lwp_rtprio(int, pid_t, lwpid_t, struct rtprio *) */

static void
show(const char *who)
{
	struct rtprio rt;

	rt.type = 0;
	if (lwp_rtprio(RTP_LOOKUP, 0, -1, &rt) < 0)
		printf("DF2794 %-7s RTP_LOOKUP errno=%d\n", who, errno);
	else
		printf("DF2794 %-7s type=%d prio=%d\n", who, rt.type, rt.prio);
}

int
main(void)
{
	struct rtprio rt;
	pid_t pid;
	int st;

	show("parent");

	pid = fork();
	if (pid == 0) {
		pause();
		_exit(0);
	}
	sleep(1);

	rt.type = RTP_PRIO_REALTIME;
	rt.prio = 31;
	printf("DF2794 RTP_SET(pid=child=%d, tid=-1, RTP_PRIO_REALTIME/31)\n", (int)pid);
	if (lwp_rtprio(RTP_SET, pid, -1, &rt) < 0)
		printf("DF2794 RTP_SET errno=%d (%s)\n", errno, strerror(errno));
	else
		printf("DF2794 RTP_SET rv=0 (success)\n");

	show("parent");		/* caller after the set */
	kill(pid, SIGKILL);
	waitpid(pid, &st, 0);

	/* the child's rtprio can no longer be read after exit; the parent's
	 * own rtprio changing from the child-directed call IS the demo */
	return 0;
}
