Kubernetes with OpenShift World Tour: Get hands-on experience and build applications fast! Find a workshop!

Access the performance monitoring unit (PMU) in AIX as a non-root user

Introduction

The performance monitoring unit (PMU) in IBM® AIX® provides the ability to monitor and count predefined events such as, processeor cycles, cache misses, instruction cache misses, and so on. The Performance-Monitor Counter registers (PMC1–PMC4) are used to record the number of times a certain event has occurred and the Monitor Mode Control registers (MMCR0–MMCR1) are used to enable various performance monitor interrupt functions and select events to count. Users can exploit these registers using libpmapi library in AIX.

In earlier releases of AIX, users could write their own profiling application using the libpmapi library without restricted access to the PMU. However, starting with AIX 6.1 TL SP, AIX 7.1 TL5, AIX 7.2 TL3, AIX 7.2 TL2 SP2-1832, and later releases, a framework was added to restrict access to the PMU to root and privileged role-based access control (RBAC) users. A root user can control access to the PMU by modifying the pmuaccess attribute in sys0. When the pmuaccess attribute in sys0 is set to priv, access to the PMU is available only to the root user and privileged role-based access control (RBAC) users. This tutorial descirbes how to create the roles and privledges required for non-root user applications to access the PMU through the libpmapi library.

Refer to the “Access controls to use PMU” documentation in the IBM Knowledge Center for more details.

Prerequisites

The following prerequisites are required to create roles and privileges for an non-root user to run PMU applications:

  • Knowledge of RBAC Framework in AIX
  • Knowledge of libpmapi library in AIX
  • Knowledge of shipped performance commands such as hpmcount, hpmstat, and so on

Estimated time

It should take approximately 30 minutes to create RBAC access for a non-root user to execute performance commands written using libpmapi library.

Steps

Add roles and privileges for commands that use the libpmapi library

For the purpose of this tutorial, we created a non-root user, pmuuser, with no PMU access authorization or roles. We’ll use a simple self-profiler application written using the libpmapi library; the compiled binary file is called selfprofiler. The sample binary code is included later in this section.

Perform the following steps to grant privileges and add a role for an application written using libpmapi library.

  1. Verify the pmuaccess attribute is set to priv by running the lsattr command with the following options:

    #lsattr -E -l sys0 -a pmuaccess
    pmuaccess priv PMU access control True
    

    The output of the command shows that pmuaccess is set to priv, which means that only root or RBAC privileged users can access the PMU.

    Note that pmuaccess is not set to priv by default. If pmuaccess is not set to priv then review the following IBM Knowledge Center article, “Access controls to use PMU”, which describes what values pmuaccess can have and how to change them if necessary.

  2. Check whether any roles are associated with the user, pmuuser, by running the lsuser command:

     #lsuser -a default_roles roles pmuuser  
     pmuuser default_roles= roles=
    

    From the above output, you can see that there are no roles associated with pmuuser.

  3. Identify which privileges are required to run the binary file, selfprofiler, by running the tracepriv command:

    # tracepriv -ef /home/ravi/pmudoc/selfprofiler
    5000090112.000000:100001.000000
    PMU Counters
    4421605,4421605,1807005,1771053,1771053,4421605,
    11796980: Used privileges for /home/ravi/pmudoc/selfprofiler:
    PV_PMU_THREAD
    

    Note: All the privleges that are reported in the output of the tracepriv command must be added to the user in order to run the binary file. In the above case, PV_PMU_THREAD is the only privilege. There may be more in other binaries.

  4. Create authorization by running the mkauth command.

    PV_PMU_THREAD is the required privilege to run the PMU application. After identifying the required privilege, create an authorization, pmu_auth, using the mkauth command. This authorization is later used as an argument in the setsecattr command to associate the selfprofiler binary file and the privilege found in the previous step.

    #mkauth pmu_auth
    
  5. Create a role for the user and link the role to the authorization using the mkrole command:

    mkrole authorizations=pmu_auth pmu_role
    
  6. Assign the new role to the user by using the chuser command:

    chuser roles=pmu_role default_roles=pmu_role pmuuser
    
  7. Set the security attribute to the binary file using the setsecattr command:

    setsecattr -c accessauths=pmu_auth innateprivs=PV_PMU_THREAD secflags=FSF_EPS /home/ravi/pmudoc/selfprofiler
    
  8. Commit the changes to the kernel security table by using the setkst command:

    # setkst
    Successfully updated the Kernel Authorization Table.
    Successfully updated the Kernel Role Table.
    Successfully updated the Kernel Command Table.
    Successfully updated the Kernel Device Table.
    Successfully updated the Kernel Object Domain Table.
    Successfully updated the Kernel Domains Table.
    Successfully updated the Kernel RBAC log level.
    

    Note: The tracpriv command can’t be used to trace the privileges of a daemon process. You can instead use the rbacqry command.

Sample code for self-profiler binary file

The following sample code is used to build the selfprofiler binary file used in the above examples:

#include <pmapi.h>
int main() {
        pm_info2_t pminfo;
        pm_groups_info_t ginfo;
        int rc = 0;
        rc = pm_initialize(PM_UNVERIFIED|PM_CAVEAT|PM_VERIFIED|PM_GET_GROUPS, &pminfo, &ginfo, PM_CURRENT);
        if(rc != 0) {
                pm_error((char *) " pm_initialize failed ",rc);
                return 1;
        }
        pm_prog_t prog;
        prog.mode.w = 0;
        prog.mode.b.user = 1;
        prog.mode.b.kernel = 1;
        prog.mode.b.is_group = 1;
        for(int i = 0; i < pminfo.maxpmcs; i++) {
                prog.events[i] = COUNT_NOTHING;
        }
        prog.events[0] = 0;
        rc = pm_set_program_mythread(&prog);
        if(rc != 0) {
                pm_error("pm_set_program_mythread",rc);
                return 1;
        }
        rc = pm_start_mythread();
        if(rc != 0) {
                pm_error("pm_start_mythread",rc);
                return 1;
        }
        /* Do some work */
        float xf = 1.0;
        float yf = 1.0;
        for(int i = 0; i < 100000; i++) {
                xf += yf + 1;
                yf += 1.0;
        }
        printf("%f:%f\n",xf,yf);
        pm_data_t pmresults = { 0 };
        rc = pm_get_data_mythread(&pmresults);
        if(rc != 0) {
                pm_error("pm_get_mythread",rc);
                return 1;
        }
        rc = pm_stop_mythread();
        if(rc != 0) {
                pm_error("pm_stop_mythread",rc);
                return 1;
        }
        printf("PMU Counters \n");
        for (int j = 0; j < pminfo.maxpmcs; j++) {
                printf("%llu,",pmresults.accu[j]);
        }
        printf("\n");
        rc = pm_delete_program_mythread();
        if(rc != 0) {
                pm_error("pm_delete_mythread",rc);
                return 1;
        }
}

Assign roles and privileges for shipped performance commands

Non-root users can’t run the shipped performance commands such as, hpmcount, hpmstat, and so on. This section outlines the steps for creating roles for the user so they can access these commands.

For illustration purposes, we used hpmcount, however, the same steps are applicable for other applications.

  1. List the security attributes for the binary file, hpmcount, by using the lssecattr command:

    # lssecattr -c /usr/pmapi/tools/hpmcount
    /usr/pmapi/tools/hpmcount accessauths=aix.system.pmustat.thread innateprivs=PV_PMU_CONFIG,PV_PMU_THREAD secflags=FSF_EPS
    

    aix.system.pmustat.thread is the authorization that is required to run hpmcount as a non-root user. The next step is to create a role and then link the aix.system.pmustat.thread authorization to that role.

  2. Create a role and link the role to the authorization by using the mkrole command:

    #mkrole authorizations= aix.system.pmustat.thread pmuroleauth
    
  3. Assign the new role to the user by using the chuser command:

    #chuser roles=pmuroleauth default_roles=pmuroleauth pmuuser
    
  4. Commit the changes to the kernel security table by using the setkst command:

    # setkst
    Successfully updated the Kernel Authorization Table.
    Successfully updated the Kernel Role Table.
    Successfully updated the Kernel Command Table.
    Successfully updated the Kernel Device Table.
    Successfully updated the Kernel Object Domain Table.
    Successfully updated the Kernel Domains Table.
    Successfully updated the Kernel RBAC log level.
    

Summary

By following the steps described in this tutorial, you can create roles and privileges that allow a non-root user to run profiling applications written using the libpmapi library.

Ravi Kumar Somashekariah