#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 *
***********************************************/
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 *
****************************************/