[CC += Thomas Gleixner] Thomas G, I expect that the small change at Thomas P proposes in this patch is correct (i.e., iopl(2) operates per-thread, not per-process). I remember that you touch the relevant kernel source file often. Perhaps you are able to give a quick Ack? Thanks, Michael On Sun, 24 May 2020 at 15:22, Thomas Piekarski <t.piekarski@xxxxxxxxxxxxxx> wrote: > > iopl is setting permissions for port-mapped I/O not per-process but only > for threads and its children. > > See https://bugzilla.kernel.org/show_bug.cgi?id=205317 > > Reported-by: victorm007@xxxxxxxxx > Signed-off-by: Thomas Piekarski <t.piekarski@xxxxxxxxxxxxxx> > > > --- > > > 1. Test case if permissions are granted per-process or per-thread > > I took the opportunity to dig into PMIO and granting permissions with > iopl and ioperm. > > Wrote the following code in which two threads are created and try to > read some data with inb(). First thread (read_from_sleepy_child) is > created before permissions are granted (but is delayed) and the second > one (read_from_child) after that. > > If those permissions would be granted on process level should the first > thread not succeed? > > I hope I did not make any mistake, applied threading well and can solve > this issue as well as support the discussion at LKML. > > 2. Test Code > > #include <pthread.h> > #include <stdio.h> > #include <sys/io.h> > #include <unistd.h> > > #define PORT 0x378 // lp0 > > void *read_from_sleepy_child() > { > sleep(3); > > // The inb() will fail due to missing permissions and it'll segfault > // although permissions are acquired before threads are joined. > // When permissions are set per process this should work. > printf("Read anything from (sleepy) child thread (%x).\n", inb(PORT)); > > return NULL; > } > > void *read_from_child() > { > // The inb() will succeed due to permissions are inherited to > // childs after they got acquired with either iopl or ioperm > printf("Read anything from child thread (%x).\n", inb(PORT)); > > return NULL; > } > > int main() > { > pthread_t delayed_thread, thread; > > pthread_create(&delayed_thread, NULL, read_from_sleepy_child, NULL); > > iopl(3); > // ioperm(0, 0xFFFF, 1); // the same segfault > > // The inb() will succeed due to being the main, default thread > // where permissions got acquired in first place > printf("Read anything from main thread (%x).\n", inb(PORT)); > > pthread_create(&thread, NULL, read_from_child, NULL); > pthread_join(delayed_thread, NULL); > pthread_join(thread, NULL); > > return 0; > } > > > 3. Patch > > man2/iopl.2 | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/man2/iopl.2 b/man2/iopl.2 > index e5b216a14..329095808 100644 > --- a/man2/iopl.2 > +++ b/man2/iopl.2 > @@ -39,7 +39,7 @@ iopl \- change I/O privilege level > .BI "int iopl(int " level ); > .SH DESCRIPTION > .BR iopl () > -changes the I/O privilege level of the calling process, > +changes the I/O privilege level of the calling thread, > as specified by the two least significant bits in > .IR level . > .PP > @@ -50,7 +50,7 @@ Since these X servers require access to all 65536 I/O > ports, the > call is not sufficient. > .PP > In addition to granting unrestricted I/O port access, running at a higher > -I/O privilege level also allows the process to disable interrupts. > +I/O privilege level also allows the thread to disable interrupts. > This will probably crash the system, and is not recommended. > .PP > Permissions are not inherited by the child process created by > @@ -79,7 +79,7 @@ is greater than 3. > This call is unimplemented. > .TP > .B EPERM > -The calling process has insufficient privilege to call > +The calling thread has insufficient privilege to call > .BR iopl (); > the > .B CAP_SYS_RAWIO > -- > 2.20.1 -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/