Loading security/smack/smack.h +11 −2 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ */ struct smack_known { struct list_head list; struct hlist_node smk_hashed; char *smk_known; u32 smk_secid; struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ Loading Loading @@ -167,9 +168,13 @@ struct smk_port_label { #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ #define SMACK_CIPSO_MAPPED_DEFAULT 251 /* Also arbitrary */ #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ /* * CIPSO 2.2 standard is 239, but Smack wants to use the * categories in a structured way that limits the value to * the bits in 23 bytes, hence the unusual number. */ #define SMACK_CIPSO_MAXCATNUM 184 /* 23 * 8 */ /* * Flag for transmute access Loading Loading @@ -222,6 +227,7 @@ char *smk_parse_smack(const char *string, int len); int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); char *smk_import(const char *, int); struct smack_known *smk_import_entry(const char *, int); void smk_insert_entry(struct smack_known *skp); struct smack_known *smk_find_entry(const char *); u32 smack_to_secid(const char *); Loading @@ -247,6 +253,9 @@ extern struct list_head smk_netlbladdr_list; extern struct security_operations smack_ops; #define SMACK_HASH_SLOTS 16 extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; /* * Is the directory transmuting? */ Loading security/smack/smack_access.c +26 −3 Original line number Diff line number Diff line Loading @@ -325,6 +325,25 @@ void smack_log(char *subject_label, char *object_label, int request, DEFINE_MUTEX(smack_known_lock); struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; /** * smk_insert_entry - insert a smack label into a hash map, * * this function must be called under smack_known_lock */ void smk_insert_entry(struct smack_known *skp) { unsigned int hash; struct hlist_head *head; hash = full_name_hash(skp->smk_known, strlen(skp->smk_known)); head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; hlist_add_head_rcu(&skp->smk_hashed, head); list_add_rcu(&skp->list, &smack_known_list); } /** * smk_find_entry - find a label on the list, return the list entry * @string: a text string that might be a Smack label Loading @@ -334,12 +353,16 @@ DEFINE_MUTEX(smack_known_lock); */ struct smack_known *smk_find_entry(const char *string) { unsigned int hash; struct hlist_head *head; struct smack_known *skp; list_for_each_entry_rcu(skp, &smack_known_list, list) { hash = full_name_hash(string, strlen(string)); head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; hlist_for_each_entry_rcu(skp, head, smk_hashed) if (strcmp(skp->smk_known, string) == 0) return skp; } return NULL; } Loading Loading @@ -475,7 +498,7 @@ struct smack_known *smk_import_entry(const char *string, int len) * Make sure that the entry is actually * filled before putting it on the list. */ list_add_rcu(&skp->list, &smack_known_list); smk_insert_entry(skp); goto unlockout; } /* Loading security/smack/smack_lsm.c +30 −12 Original line number Diff line number Diff line Loading @@ -3063,6 +3063,8 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, { struct smack_known *skp; int found = 0; int acat; int kcat; if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { /* Loading @@ -3079,13 +3081,29 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, list_for_each_entry(skp, &smack_known_list, list) { if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl) continue; if (memcmp(sap->attr.mls.cat, /* * Compare the catsets. Use the netlbl APIs. */ if ((sap->flags & NETLBL_SECATTR_MLS_CAT) == 0) { if ((skp->smk_netlabel.flags & NETLBL_SECATTR_MLS_CAT) == 0) found = 1; break; } for (acat = -1, kcat = -1; acat == kcat; ) { acat = netlbl_secattr_catmap_walk( sap->attr.mls.cat, acat + 1); kcat = netlbl_secattr_catmap_walk( skp->smk_netlabel.attr.mls.cat, SMK_CIPSOLEN) != 0) continue; kcat + 1); if (acat < 0 || kcat < 0) break; } if (acat == kcat) { found = 1; break; } } rcu_read_unlock(); if (found) Loading Loading @@ -3876,12 +3894,12 @@ static __init void init_smack_known_list(void) /* * Create the known labels list */ list_add(&smack_known_huh.list, &smack_known_list); list_add(&smack_known_hat.list, &smack_known_list); list_add(&smack_known_star.list, &smack_known_list); list_add(&smack_known_floor.list, &smack_known_list); list_add(&smack_known_invalid.list, &smack_known_list); list_add(&smack_known_web.list, &smack_known_list); smk_insert_entry(&smack_known_huh); smk_insert_entry(&smack_known_hat); smk_insert_entry(&smack_known_star); smk_insert_entry(&smack_known_floor); smk_insert_entry(&smack_known_invalid); smk_insert_entry(&smack_known_web); } /** Loading security/smack/smackfs.c +83 −97 Original line number Diff line number Diff line Loading @@ -368,56 +368,43 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule, * @data: string to be parsed, null terminated * @rule: Will be filled with Smack parsed rule * @import: if non-zero, import labels * @change: if non-zero, data is from /smack/change-rule * @tokens: numer of substrings expected in data * * Returns 0 on success, -1 on failure * Returns number of processed bytes on success, -1 on failure. */ static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule, int import, int change) static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, int import, int tokens) { char *subject; char *object; char *access1; char *access2; int datalen; int rc = -1; ssize_t cnt = 0; char *tok[4]; int i; /* This is inefficient */ datalen = strlen(data); /* * Parsing the rule in-place, filling all white-spaces with '\0' */ for (i = 0; i < tokens; ++i) { while (isspace(data[cnt])) data[cnt++] = '\0'; /* Our first element can be 64 + \0 with no spaces */ subject = kzalloc(datalen + 1, GFP_KERNEL); if (subject == NULL) if (data[cnt] == '\0') /* Unexpected end of data */ return -1; object = kzalloc(datalen, GFP_KERNEL); if (object == NULL) goto free_out_s; access1 = kzalloc(datalen, GFP_KERNEL); if (access1 == NULL) goto free_out_o; access2 = kzalloc(datalen, GFP_KERNEL); if (access2 == NULL) goto free_out_a; if (change) { if (sscanf(data, "%s %s %s %s", subject, object, access1, access2) == 4) rc = smk_fill_rule(subject, object, access1, access2, rule, import, 0); } else { if (sscanf(data, "%s %s %s", subject, object, access1) == 3) rc = smk_fill_rule(subject, object, access1, NULL, rule, import, 0); } kfree(access2); free_out_a: kfree(access1); free_out_o: kfree(object); free_out_s: kfree(subject); return rc; tok[i] = data + cnt; while (data[cnt] && !isspace(data[cnt])) ++cnt; } while (isspace(data[cnt])) data[cnt++] = '\0'; while (i < 4) tok[i++] = NULL; if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0)) return -1; return cnt; } #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ Loading Loading @@ -447,11 +434,12 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, struct list_head *rule_list, struct mutex *rule_lock, int format) { struct smack_parsed_rule *rule; struct smack_parsed_rule rule; char *data; int datalen; int rc = -EINVAL; int load = 0; int rc; int trunc = 0; int tokens; ssize_t cnt = 0; /* * No partial writes. Loading @@ -466,11 +454,14 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, */ if (count != SMK_OLOADLEN && count != SMK_LOADLEN) return -EINVAL; datalen = SMK_LOADLEN; } else datalen = count + 1; } else { if (count >= PAGE_SIZE) { count = PAGE_SIZE - 1; trunc = 1; } } data = kzalloc(datalen, GFP_KERNEL); data = kmalloc(count + 1, GFP_KERNEL); if (data == NULL) return -ENOMEM; Loading @@ -479,47 +470,49 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, goto out; } rule = kzalloc(sizeof(*rule), GFP_KERNEL); if (rule == NULL) { rc = -ENOMEM; /* * In case of parsing only part of user buf, * avoid having partial rule at the data buffer */ if (trunc) { while (count > 0 && (data[count - 1] != '\n')) --count; if (count == 0) { rc = -EINVAL; goto out; } } if (format == SMK_LONG_FMT) { /* * Be sure the data string is terminated. */ data[count] = '\0'; if (smk_parse_long_rule(data, rule, 1, 0)) goto out_free_rule; } else if (format == SMK_CHANGE_FMT) { data[count] = '\0'; if (smk_parse_long_rule(data, rule, 1, 1)) goto out_free_rule; tokens = (format == SMK_CHANGE_FMT ? 4 : 3); while (cnt < count) { if (format == SMK_FIXED24_FMT) { rc = smk_parse_rule(data, &rule, 1); if (rc != 0) { rc = -EINVAL; goto out; } cnt = count; } else { /* * More on the minor hack for backward compatibility */ if (count == (SMK_OLOADLEN)) data[SMK_OLOADLEN] = '-'; if (smk_parse_rule(data, rule, 1)) goto out_free_rule; rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens); if (rc <= 0) { rc = -EINVAL; goto out; } if (rule_list == NULL) { load = 1; rule_list = &rule->smk_subject->smk_rules; rule_lock = &rule->smk_subject->smk_rules_lock; cnt += rc; } rc = smk_set_access(rule, rule_list, rule_lock, load); if (rc == 0) { rc = count; if (rule_list == NULL) rc = smk_set_access(&rule, &rule.smk_subject->smk_rules, &rule.smk_subject->smk_rules_lock, 1); else rc = smk_set_access(&rule, rule_list, rule_lock, 0); if (rc) goto out; } out_free_rule: kfree(rule); rc = cnt; out: kfree(data); return rc; Loading Loading @@ -901,7 +894,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, for (i = 0; i < catlen; i++) { rule += SMK_DIGITLEN; ret = sscanf(rule, "%u", &cat); if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL) if (ret != 1 || cat > SMACK_CIPSO_MAXCATNUM) goto out; smack_catset_bit(cat, mapcatset); Loading Loading @@ -1840,7 +1833,6 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, { struct smack_parsed_rule rule; char *data; char *cod; int res; data = simple_transaction_get(file, buf, count); Loading @@ -1853,18 +1845,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, res = smk_parse_rule(data, &rule, 0); } else { /* * Copy the data to make sure the string is terminated. * simple_transaction_get() returns null-terminated data */ cod = kzalloc(count + 1, GFP_KERNEL); if (cod == NULL) return -ENOMEM; memcpy(cod, data, count); cod[count] = '\0'; res = smk_parse_long_rule(cod, &rule, 0, 0); kfree(cod); res = smk_parse_long_rule(data, &rule, 0, 3); } if (res) if (res < 0) return -EINVAL; res = smk_access(rule.smk_subject, rule.smk_object, Loading Loading
security/smack/smack.h +11 −2 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ */ struct smack_known { struct list_head list; struct hlist_node smk_hashed; char *smk_known; u32 smk_secid; struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ Loading Loading @@ -167,9 +168,13 @@ struct smk_port_label { #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ #define SMACK_CIPSO_MAPPED_DEFAULT 251 /* Also arbitrary */ #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ /* * CIPSO 2.2 standard is 239, but Smack wants to use the * categories in a structured way that limits the value to * the bits in 23 bytes, hence the unusual number. */ #define SMACK_CIPSO_MAXCATNUM 184 /* 23 * 8 */ /* * Flag for transmute access Loading Loading @@ -222,6 +227,7 @@ char *smk_parse_smack(const char *string, int len); int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); char *smk_import(const char *, int); struct smack_known *smk_import_entry(const char *, int); void smk_insert_entry(struct smack_known *skp); struct smack_known *smk_find_entry(const char *); u32 smack_to_secid(const char *); Loading @@ -247,6 +253,9 @@ extern struct list_head smk_netlbladdr_list; extern struct security_operations smack_ops; #define SMACK_HASH_SLOTS 16 extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; /* * Is the directory transmuting? */ Loading
security/smack/smack_access.c +26 −3 Original line number Diff line number Diff line Loading @@ -325,6 +325,25 @@ void smack_log(char *subject_label, char *object_label, int request, DEFINE_MUTEX(smack_known_lock); struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; /** * smk_insert_entry - insert a smack label into a hash map, * * this function must be called under smack_known_lock */ void smk_insert_entry(struct smack_known *skp) { unsigned int hash; struct hlist_head *head; hash = full_name_hash(skp->smk_known, strlen(skp->smk_known)); head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; hlist_add_head_rcu(&skp->smk_hashed, head); list_add_rcu(&skp->list, &smack_known_list); } /** * smk_find_entry - find a label on the list, return the list entry * @string: a text string that might be a Smack label Loading @@ -334,12 +353,16 @@ DEFINE_MUTEX(smack_known_lock); */ struct smack_known *smk_find_entry(const char *string) { unsigned int hash; struct hlist_head *head; struct smack_known *skp; list_for_each_entry_rcu(skp, &smack_known_list, list) { hash = full_name_hash(string, strlen(string)); head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; hlist_for_each_entry_rcu(skp, head, smk_hashed) if (strcmp(skp->smk_known, string) == 0) return skp; } return NULL; } Loading Loading @@ -475,7 +498,7 @@ struct smack_known *smk_import_entry(const char *string, int len) * Make sure that the entry is actually * filled before putting it on the list. */ list_add_rcu(&skp->list, &smack_known_list); smk_insert_entry(skp); goto unlockout; } /* Loading
security/smack/smack_lsm.c +30 −12 Original line number Diff line number Diff line Loading @@ -3063,6 +3063,8 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, { struct smack_known *skp; int found = 0; int acat; int kcat; if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { /* Loading @@ -3079,13 +3081,29 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, list_for_each_entry(skp, &smack_known_list, list) { if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl) continue; if (memcmp(sap->attr.mls.cat, /* * Compare the catsets. Use the netlbl APIs. */ if ((sap->flags & NETLBL_SECATTR_MLS_CAT) == 0) { if ((skp->smk_netlabel.flags & NETLBL_SECATTR_MLS_CAT) == 0) found = 1; break; } for (acat = -1, kcat = -1; acat == kcat; ) { acat = netlbl_secattr_catmap_walk( sap->attr.mls.cat, acat + 1); kcat = netlbl_secattr_catmap_walk( skp->smk_netlabel.attr.mls.cat, SMK_CIPSOLEN) != 0) continue; kcat + 1); if (acat < 0 || kcat < 0) break; } if (acat == kcat) { found = 1; break; } } rcu_read_unlock(); if (found) Loading Loading @@ -3876,12 +3894,12 @@ static __init void init_smack_known_list(void) /* * Create the known labels list */ list_add(&smack_known_huh.list, &smack_known_list); list_add(&smack_known_hat.list, &smack_known_list); list_add(&smack_known_star.list, &smack_known_list); list_add(&smack_known_floor.list, &smack_known_list); list_add(&smack_known_invalid.list, &smack_known_list); list_add(&smack_known_web.list, &smack_known_list); smk_insert_entry(&smack_known_huh); smk_insert_entry(&smack_known_hat); smk_insert_entry(&smack_known_star); smk_insert_entry(&smack_known_floor); smk_insert_entry(&smack_known_invalid); smk_insert_entry(&smack_known_web); } /** Loading
security/smack/smackfs.c +83 −97 Original line number Diff line number Diff line Loading @@ -368,56 +368,43 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule, * @data: string to be parsed, null terminated * @rule: Will be filled with Smack parsed rule * @import: if non-zero, import labels * @change: if non-zero, data is from /smack/change-rule * @tokens: numer of substrings expected in data * * Returns 0 on success, -1 on failure * Returns number of processed bytes on success, -1 on failure. */ static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule, int import, int change) static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, int import, int tokens) { char *subject; char *object; char *access1; char *access2; int datalen; int rc = -1; ssize_t cnt = 0; char *tok[4]; int i; /* This is inefficient */ datalen = strlen(data); /* * Parsing the rule in-place, filling all white-spaces with '\0' */ for (i = 0; i < tokens; ++i) { while (isspace(data[cnt])) data[cnt++] = '\0'; /* Our first element can be 64 + \0 with no spaces */ subject = kzalloc(datalen + 1, GFP_KERNEL); if (subject == NULL) if (data[cnt] == '\0') /* Unexpected end of data */ return -1; object = kzalloc(datalen, GFP_KERNEL); if (object == NULL) goto free_out_s; access1 = kzalloc(datalen, GFP_KERNEL); if (access1 == NULL) goto free_out_o; access2 = kzalloc(datalen, GFP_KERNEL); if (access2 == NULL) goto free_out_a; if (change) { if (sscanf(data, "%s %s %s %s", subject, object, access1, access2) == 4) rc = smk_fill_rule(subject, object, access1, access2, rule, import, 0); } else { if (sscanf(data, "%s %s %s", subject, object, access1) == 3) rc = smk_fill_rule(subject, object, access1, NULL, rule, import, 0); } kfree(access2); free_out_a: kfree(access1); free_out_o: kfree(object); free_out_s: kfree(subject); return rc; tok[i] = data + cnt; while (data[cnt] && !isspace(data[cnt])) ++cnt; } while (isspace(data[cnt])) data[cnt++] = '\0'; while (i < 4) tok[i++] = NULL; if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0)) return -1; return cnt; } #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ Loading Loading @@ -447,11 +434,12 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, struct list_head *rule_list, struct mutex *rule_lock, int format) { struct smack_parsed_rule *rule; struct smack_parsed_rule rule; char *data; int datalen; int rc = -EINVAL; int load = 0; int rc; int trunc = 0; int tokens; ssize_t cnt = 0; /* * No partial writes. Loading @@ -466,11 +454,14 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, */ if (count != SMK_OLOADLEN && count != SMK_LOADLEN) return -EINVAL; datalen = SMK_LOADLEN; } else datalen = count + 1; } else { if (count >= PAGE_SIZE) { count = PAGE_SIZE - 1; trunc = 1; } } data = kzalloc(datalen, GFP_KERNEL); data = kmalloc(count + 1, GFP_KERNEL); if (data == NULL) return -ENOMEM; Loading @@ -479,47 +470,49 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, goto out; } rule = kzalloc(sizeof(*rule), GFP_KERNEL); if (rule == NULL) { rc = -ENOMEM; /* * In case of parsing only part of user buf, * avoid having partial rule at the data buffer */ if (trunc) { while (count > 0 && (data[count - 1] != '\n')) --count; if (count == 0) { rc = -EINVAL; goto out; } } if (format == SMK_LONG_FMT) { /* * Be sure the data string is terminated. */ data[count] = '\0'; if (smk_parse_long_rule(data, rule, 1, 0)) goto out_free_rule; } else if (format == SMK_CHANGE_FMT) { data[count] = '\0'; if (smk_parse_long_rule(data, rule, 1, 1)) goto out_free_rule; tokens = (format == SMK_CHANGE_FMT ? 4 : 3); while (cnt < count) { if (format == SMK_FIXED24_FMT) { rc = smk_parse_rule(data, &rule, 1); if (rc != 0) { rc = -EINVAL; goto out; } cnt = count; } else { /* * More on the minor hack for backward compatibility */ if (count == (SMK_OLOADLEN)) data[SMK_OLOADLEN] = '-'; if (smk_parse_rule(data, rule, 1)) goto out_free_rule; rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens); if (rc <= 0) { rc = -EINVAL; goto out; } if (rule_list == NULL) { load = 1; rule_list = &rule->smk_subject->smk_rules; rule_lock = &rule->smk_subject->smk_rules_lock; cnt += rc; } rc = smk_set_access(rule, rule_list, rule_lock, load); if (rc == 0) { rc = count; if (rule_list == NULL) rc = smk_set_access(&rule, &rule.smk_subject->smk_rules, &rule.smk_subject->smk_rules_lock, 1); else rc = smk_set_access(&rule, rule_list, rule_lock, 0); if (rc) goto out; } out_free_rule: kfree(rule); rc = cnt; out: kfree(data); return rc; Loading Loading @@ -901,7 +894,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, for (i = 0; i < catlen; i++) { rule += SMK_DIGITLEN; ret = sscanf(rule, "%u", &cat); if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL) if (ret != 1 || cat > SMACK_CIPSO_MAXCATNUM) goto out; smack_catset_bit(cat, mapcatset); Loading Loading @@ -1840,7 +1833,6 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, { struct smack_parsed_rule rule; char *data; char *cod; int res; data = simple_transaction_get(file, buf, count); Loading @@ -1853,18 +1845,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, res = smk_parse_rule(data, &rule, 0); } else { /* * Copy the data to make sure the string is terminated. * simple_transaction_get() returns null-terminated data */ cod = kzalloc(count + 1, GFP_KERNEL); if (cod == NULL) return -ENOMEM; memcpy(cod, data, count); cod[count] = '\0'; res = smk_parse_long_rule(cod, &rule, 0, 0); kfree(cod); res = smk_parse_long_rule(data, &rule, 0, 3); } if (res) if (res < 0) return -EINVAL; res = smk_access(rule.smk_subject, rule.smk_object, Loading