struct nodemap_pde *nm_pde_data;
/* fileset the nodes of this nodemap are restricted to */
char nm_fileset[PATH_MAX+1];
+ /* information about the expected SELinux policy on the nodes */
+ char nm_sepol[LUSTRE_NODEMAP_SEPOL_LENGTH + 1];
/* used when loading/unloading nodemaps */
struct list_head nm_list;
const __u32 map[2]);
int nodemap_set_fileset(const char *name, const char *fileset);
char *nodemap_get_fileset(const struct lu_nodemap *nodemap);
+int nodemap_set_sepol(const char *name, const char *sepol);
+const char *nodemap_get_sepol(const struct lu_nodemap *nodemap);
__u32 nodemap_map_id(struct lu_nodemap *nodemap,
enum nodemap_id_type id_type,
enum nodemap_tree_type tree_type, __u32 id);
*/
};
+/* sepol string format is:
+ * <1-digit for SELinux status>:<policy name>:<policy version>:<policy hash>
+ */
+/* Max length of the sepol string
+ * Should be large enough to contain a sha512sum of the policy
+ */
+#define SELINUX_MODE_LEN 1
+#define SELINUX_POLICY_VER_LEN 3 /* 3 chars to leave room for the future */
+#define SELINUX_POLICY_HASH_LEN 64
+#define LUSTRE_NODEMAP_SEPOL_LENGTH (SELINUX_MODE_LEN + NAME_MAX + \
+ SELINUX_POLICY_VER_LEN + \
+ SELINUX_POLICY_HASH_LEN + 3)
+
/* nodemap records, uses 32 byte record length */
#define LUSTRE_NODEMAP_NAME_LENGTH 16
struct nodemap_cluster_rec {
case LCFG_NODEMAP_ADD_GIDMAP:
case LCFG_NODEMAP_DEL_GIDMAP:
case LCFG_NODEMAP_SET_FILESET:
+ case LCFG_NODEMAP_SET_SEPOL:
if (lcfg->lcfg_bufcount != 3)
GOTO(out_lcfg, rc = -EINVAL);
nodemap_name = lustre_cfg_string(lcfg, 1);
case LCFG_NODEMAP_SET_FILESET:
rc = nodemap_set_fileset(nodemap_name, param);
break;
+ case LCFG_NODEMAP_SET_SEPOL:
+ rc = nodemap_set_sepol(nodemap_name, param);
+ break;
default:
rc = -EINVAL;
}
}
EXPORT_SYMBOL(nodemap_get_fileset);
+static int nodemap_validate_sepol(const char *sepol)
+{
+ char buf[LUSTRE_NODEMAP_SEPOL_LENGTH + 1];
+ char *p = (char *)sepol;
+ char *q = buf;
+ char polname[NAME_MAX + 1] = "";
+ char hash[SELINUX_POLICY_HASH_LEN + 1] = "";
+ unsigned char mode;
+ unsigned short ver;
+
+ CLASSERT(sizeof(buf) == sizeof(((struct lu_nodemap *)0)->nm_sepol));
+
+ if (sepol == NULL)
+ return -EINVAL;
+
+ /* we allow sepol = "" which means clear SELinux policy info */
+ if (sepol[0] == '\0')
+ return 0;
+
+ /* make a copy of sepol, by replacing ':' with space
+ * so that we can use sscanf over the string
+ */
+ while (p-sepol < sizeof(buf)) {
+ if (*p == ':')
+ *q = ' ';
+ else
+ *q = *p;
+ if (*p == '\0')
+ break;
+ p++;
+ q++;
+ }
+ if (p-sepol == sizeof(buf))
+ return -ENAMETOOLONG;
+
+ if (sscanf(buf, "%1hhu %s %hu %s", &mode, polname, &ver, hash) != 4)
+ return -EINVAL;
+
+ if (mode != 0 && mode != 1)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * set SELinux policy on nodemap
+ * \param name nodemap to set SELinux policy info on
+ * \param sepol string containing SELinux policy info
+ * \retval 0 on success
+ *
+ * set SELinux policy info on the named nodemap
+ */
+int nodemap_set_sepol(const char *name, const char *sepol)
+{
+ struct lu_nodemap *nodemap = NULL;
+ int rc;
+
+ rc = nodemap_validate_sepol(sepol);
+ if (rc < 0)
+ GOTO(out, rc);
+
+ mutex_lock(&active_config_lock);
+ nodemap = nodemap_lookup(name);
+ if (IS_ERR(nodemap)) {
+ mutex_unlock(&active_config_lock);
+ GOTO(out, rc = PTR_ERR(nodemap));
+ }
+
+ if (is_default_nodemap(nodemap)) {
+ /* We do not want nodes in the default nodemap to have
+ * SELinux restrictions. Sec admin should create dedicated
+ * nodemap entries for this.
+ */
+ GOTO(out_putref, rc = -EINVAL);
+ }
+
+ /* truncation cannot happen, as string length was checked in
+ * nodemap_validate_sepol()
+ */
+ strlcpy(nodemap->nm_sepol, sepol, sizeof(nodemap->nm_sepol));
+
+out_putref:
+ mutex_unlock(&active_config_lock);
+ nodemap_putref(nodemap);
+out:
+ return rc;
+}
+EXPORT_SYMBOL(nodemap_set_sepol);
+
+/**
+ * get SELinux policy info defined on nodemap
+ * \param nodemap nodemap to get SELinux policy info from
+ * \retval SELinux policy info, or NULL if not defined or not activated
+ *
+ * get the SELinux policy info defined on the nodemap
+ */
+const char *nodemap_get_sepol(const struct lu_nodemap *nodemap)
+{
+ if (is_default_nodemap(nodemap))
+ return NULL;
+ else
+ return (char *)nodemap->nm_sepol;
+}
+EXPORT_SYMBOL(nodemap_get_sepol);
+
/**
* Nodemap constructor
*
nodemap->nm_squash_uid = NODEMAP_NOBODY_UID;
nodemap->nm_squash_gid = NODEMAP_NOBODY_GID;
nodemap->nm_fileset[0] = '\0';
+ nodemap->nm_sepol[0] = '\0';
if (!is_default)
CWARN("adding nodemap '%s' to config without"
" default nodemap\n", nodemap->nm_name);
nodemap->nm_squash_uid = default_nodemap->nm_squash_uid;
nodemap->nm_squash_gid = default_nodemap->nm_squash_gid;
nodemap->nm_fileset[0] = '\0';
+ nodemap->nm_sepol[0] = '\0';
}
RETURN(nodemap);
LPROC_SEQ_FOPS(nodemap_fileset);
/**
+ * Reads and prints the SELinux policy info for the given nodemap.
+ *
+ * \param m seq file in proc fs
+ * \param data unused
+ * \retval 0 success
+ */
+static int nodemap_sepol_seq_show(struct seq_file *m, void *data)
+{
+ struct lu_nodemap *nodemap;
+ int rc = 0;
+
+ mutex_lock(&active_config_lock);
+ nodemap = nodemap_lookup(m->private);
+ mutex_unlock(&active_config_lock);
+ if (IS_ERR(nodemap)) {
+ rc = PTR_ERR(nodemap);
+ CERROR("cannot find nodemap '%s': rc = %d\n",
+ (char *)m->private, rc);
+ return rc;
+ }
+
+ seq_printf(m, "%s\n", nodemap_get_sepol(nodemap));
+ nodemap_putref(nodemap);
+ return rc;
+}
+
+/**
+ * Set SELinux policy info on a nodemap.
+ *
+ * \param[in] file proc file
+ * \param[in] buffer string, "<sepol>"
+ * \param[in] count \a buffer length
+ * \param[in] off unused
+ * \retval \a count on success
+ * \retval negative number on error
+ */
+static ssize_t
+nodemap_sepol_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
+{
+ struct seq_file *m = file->private_data;
+ char sepol[LUSTRE_NODEMAP_SEPOL_LENGTH + 1];
+ int rc = 0;
+
+ CLASSERT(sizeof(sepol) == sizeof(((struct lu_nodemap *)0)->nm_sepol));
+
+ if (count > 0) {
+ if (count >= sizeof(sepol))
+ GOTO(out, rc = -ENAMETOOLONG);
+
+ if (copy_from_user(sepol, buffer, count))
+ GOTO(out, rc = -EFAULT);
+
+ sepol[count] = '\0';
+
+ rc = nodemap_set_sepol(m->private, sepol);
+ }
+
+out:
+ if (rc != 0)
+ return rc;
+
+ return count;
+}
+LPROC_SEQ_FOPS(nodemap_sepol);
+
+/**
* Reads and prints the exports attached to the given nodemap.
*
* \param m seq file in proc fs, stores nodemap
.fops = &nodemap_fileset_fops,
},
{
+ .name = "sepol",
+ .fops = &nodemap_sepol_fops,
+ },
+ {
.name = "exports",
.fops = &nodemap_exports_fops,
},
{"nodemap_set_fileset", jt_nodemap_set_fileset, 0,
"set a fileset on a nodemap\n"
"usage: nodemap_set_fileset <fileset>"},
+ {"nodemap_set_sepol", jt_nodemap_set_sepol, 0,
+ "set SELinux policy info on a nodemap\n"
+ "usage: nodemap_set_sepol <SELinux policy info>"},
{"nodemap_test_nid", jt_nodemap_test_nid, 0,
"usage: nodemap_test_nid <nid>"},
{"nodemap_test_id", jt_nodemap_test_id, 0,
}
/**
+ * set SELinux policy info on a nodemap
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * --name nodemap name
+ * --sepol SELinux policy info
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_set_sepol(int argc, char **argv)
+{
+ char *nodemap_name = NULL;
+ char *sepol = NULL;
+ int rc = 0;
+ int c;
+
+ static struct option long_options[] = {
+ {
+ .name = "name",
+ .has_arg = required_argument,
+ .val = 'n',
+ },
+ {
+ .name = "sepol",
+ .has_arg = required_argument,
+ .val = 's',
+ },
+ {
+ .name = NULL,
+ }
+ };
+
+ while ((c = getopt_long(argc, argv, "n:s:",
+ long_options, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nodemap_name = optarg;
+ break;
+ case 's':
+ sepol = optarg;
+ break;
+ }
+ }
+
+ if (nodemap_name == NULL || sepol == NULL) {
+ fprintf(stderr, "usage: nodemap_set_sepol --name <name> "
+ "--sepol <sepol>\n");
+ return -1;
+ }
+
+ rc = nodemap_cmd(LCFG_NODEMAP_SET_SEPOL, NULL, 0, argv[0],
+ nodemap_name, sepol, NULL);
+ if (rc != 0) {
+ errno = -rc;
+ fprintf(stderr, "error: %s: cannot set sepol '%s' on nodemap "
+ "'%s': rc = %d\n",
+ jt_cmdname(argv[0]), sepol, nodemap_name, rc);
+ }
+
+ return rc;
+}
+
+/**
* modify a nodemap's behavior
*
* \param argc number of args
int jt_nodemap_del_idmap(int argc, char **argv);
int jt_nodemap_test_id(int argc, char **argv);
int jt_nodemap_set_fileset(int argc, char **argv);
+int jt_nodemap_set_sepol(int argc, char **argv);
int jt_nodemap_info(int argc, char **argv);
int jt_changelog_register(int argc, char **argv);
int jt_changelog_deregister(int argc, char **argv);