Whamcloud - gitweb
LU-8955 sec: create new function sptlrpc_get_sepol()
[fs/lustre-release.git] / lustre / ptlrpc / sec.c
index 5c44f89..666510a 100644 (file)
 
 #include "ptlrpc_internal.h"
 
+static int send_sepol;
+module_param(send_sepol, int, 0644);
+MODULE_PARM_DESC(send_sepol, "Client sends SELinux policy status");
+
 /***********************************************
  * policy registers                            *
  ***********************************************/
@@ -1746,6 +1750,125 @@ int sptlrpc_svc_install_rvs_ctx(struct obd_import *imp,
         return policy->sp_sops->install_rctx(imp, ctx);
 }
 
+/* Get SELinux policy info from userspace */
+static int sepol_helper(struct obd_import *imp)
+{
+       char mtime_str[21] = { 0 }, mode_str[2] = { 0 };
+       char *argv[] = {
+               [0] = "/usr/sbin/l_getsepol",
+               [1] = "-o",
+               [2] = NULL,         /* obd type */
+               [3] = "-n",
+               [4] = NULL,         /* obd name */
+               [5] = "-t",
+               [6] = mtime_str,    /* policy mtime */
+               [7] = "-m",
+               [8] = mode_str,     /* enforcing mode */
+               [9] = NULL
+       };
+       char *envp[] = {
+               [0] = "HOME=/",
+               [1] = "PATH=/sbin:/usr/sbin",
+               [2] = NULL
+       };
+       signed short ret;
+       int rc = 0;
+
+       if (imp == NULL || imp->imp_obd == NULL ||
+           imp->imp_obd->obd_type == NULL) {
+               rc = -EINVAL;
+       } else {
+               argv[2] = imp->imp_obd->obd_type->typ_name;
+               argv[4] = imp->imp_obd->obd_name;
+               spin_lock(&imp->imp_sec->ps_lock);
+               if (imp->imp_sec->ps_sepol_mtime == 0 &&
+                   imp->imp_sec->ps_sepol[0] == '\0') {
+                       /* ps_sepol has not been initialized */
+                       argv[5] = NULL;
+                       argv[7] = NULL;
+               } else {
+                       snprintf(mtime_str, sizeof(mtime_str), "%lu",
+                                imp->imp_sec->ps_sepol_mtime);
+                       mode_str[0] = imp->imp_sec->ps_sepol[0];
+               }
+               spin_unlock(&imp->imp_sec->ps_lock);
+               ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+               rc = ret>>8;
+       }
+
+       return rc;
+}
+
+static inline int sptlrpc_sepol_needs_check(struct ptlrpc_sec *imp_sec)
+{
+       ktime_t checknext;
+
+       if (send_sepol == 0 || !selinux_is_enabled())
+               return 0;
+
+       if (send_sepol == -1)
+               /* send_sepol == -1 means fetch sepol status every time */
+               return 1;
+
+       spin_lock(&imp_sec->ps_lock);
+       checknext = imp_sec->ps_sepol_checknext;
+       spin_unlock(&imp_sec->ps_lock);
+
+       /* next check is too far in time, please update */
+       if (ktime_after(checknext,
+                       ktime_add(ktime_get(), ktime_set(send_sepol, 0))))
+               goto setnext;
+
+       if (ktime_before(ktime_get(), checknext))
+               /* too early to fetch sepol status */
+               return 0;
+
+setnext:
+       /* define new sepol_checknext time */
+       spin_lock(&imp_sec->ps_lock);
+       imp_sec->ps_sepol_checknext = ktime_add(ktime_get(),
+                                               ktime_set(send_sepol, 0));
+       spin_unlock(&imp_sec->ps_lock);
+
+       return 1;
+}
+
+int sptlrpc_get_sepol(struct ptlrpc_request *req)
+{
+       struct ptlrpc_sec *imp_sec = req->rq_import->imp_sec;
+       int rc = 0;
+
+       ENTRY;
+
+       (req->rq_sepol)[0] = '\0';
+
+#ifndef HAVE_SELINUX
+       if (unlikely(send_sepol != 0))
+               CDEBUG(D_SEC, "Client cannot report SELinux status, "
+                             "it was not built against libselinux.\n");
+       RETURN(0);
+#endif
+
+       if (send_sepol == 0 || !selinux_is_enabled())
+               RETURN(0);
+
+       if (imp_sec == NULL)
+               RETURN(-EINVAL);
+
+       /* Retrieve SELinux status info */
+       if (sptlrpc_sepol_needs_check(imp_sec))
+               rc = sepol_helper(req->rq_import);
+       if (likely(rc == 0)) {
+               spin_lock(&imp_sec->ps_lock);
+               memcpy(req->rq_sepol, imp_sec->ps_sepol,
+                      sizeof(req->rq_sepol));
+               spin_unlock(&imp_sec->ps_lock);
+       }
+
+       RETURN(rc);
+}
+EXPORT_SYMBOL(sptlrpc_get_sepol);
+
 /****************************************
  * server side security                 *
  ****************************************/