@@ -352,37 +352,48 @@ int upci_find_device(struct upci_dev_info *p)
352352
353353static int incr_io_usage ( void )
354354{
355- int retval , eno ;
356-
357- /* make sure we can do I/O */
358- if ( ioaccess == 0 ) {
359- /* enable access */
360- /* this needs privileges */
361- if (seteuid (0 ) != 0 ) {
362- errmsg (__func__ , "need root privileges (or setuid root)" );
363- return -1 ;
364- }
365- /* do it */
366- retval = iopl (3 );
367- eno = errno ;
368- /* drop privileges */
369- if (seteuid (getuid ()) != 0 )
370- {
371- errmsg (__func__ , "unable to drop root privileges" );
372- /* Don't continue past this point, because following code may
373- * execute with unexpected privileges
374- */
375- _exit (99 );
376- }
377- /* check result */
378- if (retval < 0 || iopl (3 ) < 0 ) {
379- errmsg (__func__ ,"opening I/O ports: %s" , strerror (eno ));
380- return -1 ;
381- }
355+ int retval = 0 , eno = 0 ;
356+
357+ /* Try iopl(3) with our existing privileges first: succeeds when
358+ * the process holds CAP_SYS_RAWIO via file caps or is already
359+ * setuid root. Only fall back to seteuid(0) if that path is closed.
360+ */
361+ do {
362+ if (ioaccess ) {
363+ break ;
364+ }
365+
366+ retval = iopl (3 );
367+ if (retval == 0 ) {
368+ break ;
369+ }
370+
371+ retval = seteuid (0 );
372+ if (retval != 0 ) {
373+ eno = errno ;
374+ break ;
375+ }
376+
377+ retval = iopl (3 );
378+ eno = errno ;
379+
380+ if (seteuid (getuid ()) != 0 ) {
381+ errmsg (__func__ , "unable to drop root privileges" );
382+ /* Don't continue past this point, because following code may
383+ * execute with unexpected privileges
384+ */
385+ _exit (99 );
386+ }
387+ } while (0 );
388+
389+ if (retval == 0 ) {
390+ /* increment reference count */
391+ ioaccess ++ ;
392+ } else {
393+ errmsg (__func__ ,"error: %s" , strerror (eno ));
382394 }
383- /* increment reference count */
384- ioaccess ++ ;
385- return 0 ;
395+
396+ return retval ;
386397}
387398
388399static void decr_io_usage ( void )
0 commit comments