···117117ambient118118 This contains the Smack label applied to unlabeled network119119 packets.120120+change-rule121121+ This interface allows modification of existing access control rules.122122+ The format accepted on write is:123123+ "%s %s %s %s"124124+ where the first string is the subject label, the second the125125+ object label, the third the access to allow and the fourth the126126+ access to deny. The access strings may contain only the characters127127+ "rwxat-". If a rule for a given subject and object exists it will be128128+ modified by enabling the permissions in the third string and disabling129129+ those in the fourth string. If there is no such rule it will be130130+ created using the access specified in the third and the fourth strings.120131cipso121132 This interface allows a specific CIPSO header to be assigned122133 to a Smack label. The format accepted on write is:
+1
include/uapi/linux/magic.h
···1111#define DEBUGFS_MAGIC 0x646267201212#define SECURITYFS_MAGIC 0x736366731313#define SELINUX_MAGIC 0xf97cff8c1414+#define SMACK_MAGIC 0x43415d53 /* "SMAC" */1415#define RAMFS_MAGIC 0x858458f6 /* some random number */1516#define TMPFS_MAGIC 0x010219941617#define HUGETLBFS_MAGIC 0x958458f6 /* some random number */
···654654 /*655655 * You also need write access to the containing directory656656 */657657- smk_ad_setfield_u_fs_path_dentry(&ad, NULL);657657+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);658658 smk_ad_setfield_u_fs_inode(&ad, dir);659659 rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);660660 }···685685 /*686686 * You also need write access to the containing directory687687 */688688- smk_ad_setfield_u_fs_path_dentry(&ad, NULL);688688+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);689689 smk_ad_setfield_u_fs_inode(&ad, dir);690690 rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);691691 }
+170-81
security/smack/smackfs.c
···5050 SMK_ACCESS2 = 16, /* make an access check with long labels */5151 SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */5252 SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */5353+ SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */5354};54555556/*5657 * List locks5758 */5858-static DEFINE_MUTEX(smack_list_lock);5959static DEFINE_MUTEX(smack_cipso_lock);6060static DEFINE_MUTEX(smack_ambient_lock);6161static DEFINE_MUTEX(smk_netlbladdr_lock);···109109};110110111111LIST_HEAD(smack_rule_list);112112+113113+struct smack_parsed_rule {114114+ char *smk_subject;115115+ char *smk_object;116116+ int smk_access1;117117+ int smk_access2;118118+};112119113120static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;114121···174167#define SMK_NETLBLADDRMIN 9175168176169/**177177- * smk_set_access - add a rule to the rule list178178- * @srp: the new rule to add170170+ * smk_set_access - add a rule to the rule list or replace an old rule171171+ * @srp: the rule to add or replace179172 * @rule_list: the list of rules180173 * @rule_lock: the rule list lock174174+ * @global: if non-zero, indicates a global rule181175 *182176 * Looks through the current subject/object/access list for183177 * the subject/object pair and replaces the access that was184178 * there. If the pair isn't found add it with the specified185179 * access.186180 *187187- * Returns 1 if a rule was found to exist already, 0 if it is new188181 * Returns 0 if nothing goes wrong or -ENOMEM if it fails189182 * during the allocation of the new pair to add.190183 */191191-static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,192192- struct mutex *rule_lock)184184+static int smk_set_access(struct smack_parsed_rule *srp,185185+ struct list_head *rule_list,186186+ struct mutex *rule_lock, int global)193187{194188 struct smack_rule *sp;189189+ struct smack_master_list *smlp;195190 int found = 0;191191+ int rc = 0;196192197193 mutex_lock(rule_lock);198194···207197 if (sp->smk_object == srp->smk_object &&208198 sp->smk_subject == srp->smk_subject) {209199 found = 1;210210- sp->smk_access = srp->smk_access;200200+ sp->smk_access |= srp->smk_access1;201201+ sp->smk_access &= ~srp->smk_access2;211202 break;212203 }213204 }214214- if (found == 0)215215- list_add_rcu(&srp->list, rule_list);216205206206+ if (found == 0) {207207+ sp = kzalloc(sizeof(*sp), GFP_KERNEL);208208+ if (sp == NULL) {209209+ rc = -ENOMEM;210210+ goto out;211211+ }212212+213213+ sp->smk_subject = srp->smk_subject;214214+ sp->smk_object = srp->smk_object;215215+ sp->smk_access = srp->smk_access1 & ~srp->smk_access2;216216+217217+ list_add_rcu(&sp->list, rule_list);218218+ /*219219+ * If this is a global as opposed to self and a new rule220220+ * it needs to get added for reporting.221221+ */222222+ if (global) {223223+ smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);224224+ if (smlp != NULL) {225225+ smlp->smk_rule = sp;226226+ list_add_rcu(&smlp->list, &smack_rule_list);227227+ } else228228+ rc = -ENOMEM;229229+ }230230+ }231231+232232+out:217233 mutex_unlock(rule_lock);234234+ return rc;235235+}218236219219- return found;237237+/**238238+ * smk_perm_from_str - parse smack accesses from a text string239239+ * @string: a text string that contains a Smack accesses code240240+ *241241+ * Returns an integer with respective bits set for specified accesses.242242+ */243243+static int smk_perm_from_str(const char *string)244244+{245245+ int perm = 0;246246+ const char *cp;247247+248248+ for (cp = string; ; cp++)249249+ switch (*cp) {250250+ case '-':251251+ break;252252+ case 'r':253253+ case 'R':254254+ perm |= MAY_READ;255255+ break;256256+ case 'w':257257+ case 'W':258258+ perm |= MAY_WRITE;259259+ break;260260+ case 'x':261261+ case 'X':262262+ perm |= MAY_EXEC;263263+ break;264264+ case 'a':265265+ case 'A':266266+ perm |= MAY_APPEND;267267+ break;268268+ case 't':269269+ case 'T':270270+ perm |= MAY_TRANSMUTE;271271+ break;272272+ default:273273+ return perm;274274+ }220275}221276222277/**223278 * smk_fill_rule - Fill Smack rule from strings224279 * @subject: subject label string225280 * @object: object label string226226- * @access: access string281281+ * @access1: access string282282+ * @access2: string with permissions to be removed227283 * @rule: Smack rule228284 * @import: if non-zero, import labels229285 * @len: label length limit···297221 * Returns 0 on success, -1 on failure298222 */299223static int smk_fill_rule(const char *subject, const char *object,300300- const char *access, struct smack_rule *rule,301301- int import, int len)224224+ const char *access1, const char *access2,225225+ struct smack_parsed_rule *rule, int import,226226+ int len)302227{303228 const char *cp;304229 struct smack_known *skp;···332255 rule->smk_object = skp->smk_known;333256 }334257335335- rule->smk_access = 0;336336-337337- for (cp = access; *cp != '\0'; cp++) {338338- switch (*cp) {339339- case '-':340340- break;341341- case 'r':342342- case 'R':343343- rule->smk_access |= MAY_READ;344344- break;345345- case 'w':346346- case 'W':347347- rule->smk_access |= MAY_WRITE;348348- break;349349- case 'x':350350- case 'X':351351- rule->smk_access |= MAY_EXEC;352352- break;353353- case 'a':354354- case 'A':355355- rule->smk_access |= MAY_APPEND;356356- break;357357- case 't':358358- case 'T':359359- rule->smk_access |= MAY_TRANSMUTE;360360- break;361361- default:362362- return 0;363363- }364364- }258258+ rule->smk_access1 = smk_perm_from_str(access1);259259+ if (access2)260260+ rule->smk_access2 = smk_perm_from_str(access2);261261+ else262262+ rule->smk_access2 = ~rule->smk_access1;365263366264 return 0;367265}···349297 *350298 * Returns 0 on success, -1 on errors.351299 */352352-static int smk_parse_rule(const char *data, struct smack_rule *rule, int import)300300+static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,301301+ int import)353302{354303 int rc;355304356305 rc = smk_fill_rule(data, data + SMK_LABELLEN,357357- data + SMK_LABELLEN + SMK_LABELLEN, rule, import,358358- SMK_LABELLEN);306306+ data + SMK_LABELLEN + SMK_LABELLEN, NULL, rule,307307+ import, SMK_LABELLEN);359308 return rc;360309}361310362311/**363312 * smk_parse_long_rule - parse Smack rule from rule string364313 * @data: string to be parsed, null terminated365365- * @rule: Smack rule314314+ * @rule: Will be filled with Smack parsed rule366315 * @import: if non-zero, import labels316316+ * @change: if non-zero, data is from /smack/change-rule367317 *368318 * Returns 0 on success, -1 on failure369319 */370370-static int smk_parse_long_rule(const char *data, struct smack_rule *rule,371371- int import)320320+static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule,321321+ int import, int change)372322{373323 char *subject;374324 char *object;375375- char *access;325325+ char *access1;326326+ char *access2;376327 int datalen;377328 int rc = -1;378329···389334 object = kzalloc(datalen, GFP_KERNEL);390335 if (object == NULL)391336 goto free_out_s;392392- access = kzalloc(datalen, GFP_KERNEL);393393- if (access == NULL)337337+ access1 = kzalloc(datalen, GFP_KERNEL);338338+ if (access1 == NULL)394339 goto free_out_o;340340+ access2 = kzalloc(datalen, GFP_KERNEL);341341+ if (access2 == NULL)342342+ goto free_out_a;395343396396- if (sscanf(data, "%s %s %s", subject, object, access) == 3)397397- rc = smk_fill_rule(subject, object, access, rule, import, 0);344344+ if (change) {345345+ if (sscanf(data, "%s %s %s %s",346346+ subject, object, access1, access2) == 4)347347+ rc = smk_fill_rule(subject, object, access1, access2,348348+ rule, import, 0);349349+ } else {350350+ if (sscanf(data, "%s %s %s", subject, object, access1) == 3)351351+ rc = smk_fill_rule(subject, object, access1, NULL,352352+ rule, import, 0);353353+ }398354399399- kfree(access);355355+ kfree(access2);356356+free_out_a:357357+ kfree(access1);400358free_out_o:401359 kfree(object);402360free_out_s:···419351420352#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */421353#define SMK_LONG_FMT 1 /* Variable long label format */354354+#define SMK_CHANGE_FMT 2 /* Rule modification format */422355/**423356 * smk_write_rules_list - write() for any /smack rule file424357 * @file: file pointer, not actually used···428359 * @ppos: where to start - must be 0429360 * @rule_list: the list of rules to write to430361 * @rule_lock: lock for the rule list431431- * @format: /smack/load or /smack/load2 format.362362+ * @format: /smack/load or /smack/load2 or /smack/change-rule format.432363 *433364 * Get one smack access rule from above.434365 * The format for SMK_LONG_FMT is:435366 * "subject<whitespace>object<whitespace>access[<whitespace>...]"436367 * The format for SMK_FIXED24_FMT is exactly:437368 * "subject object rwxat"369369+ * The format for SMK_CHANGE_FMT is:370370+ * "subject<whitespace>object<whitespace>371371+ * acc_enable<whitespace>acc_disable[<whitespace>...]"438372 */439373static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,440374 size_t count, loff_t *ppos,441375 struct list_head *rule_list,442376 struct mutex *rule_lock, int format)443377{444444- struct smack_master_list *smlp;445378 struct smack_known *skp;446446- struct smack_rule *rule;379379+ struct smack_parsed_rule *rule;447380 char *data;448381 int datalen;449382 int rc = -EINVAL;···488417 * Be sure the data string is terminated.489418 */490419 data[count] = '\0';491491- if (smk_parse_long_rule(data, rule, 1))420420+ if (smk_parse_long_rule(data, rule, 1, 0))421421+ goto out_free_rule;422422+ } else if (format == SMK_CHANGE_FMT) {423423+ data[count] = '\0';424424+ if (smk_parse_long_rule(data, rule, 1, 1))492425 goto out_free_rule;493426 } else {494427 /*···512437 rule_lock = &skp->smk_rules_lock;513438 }514439515515- rc = count;516516- /*517517- * If this is a global as opposed to self and a new rule518518- * it needs to get added for reporting.519519- * smk_set_access returns true if there was already a rule520520- * for the subject/object pair, and false if it was new.521521- */522522- if (!smk_set_access(rule, rule_list, rule_lock)) {523523- if (load) {524524- smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);525525- if (smlp != NULL) {526526- smlp->smk_rule = rule;527527- list_add_rcu(&smlp->list, &smack_rule_list);528528- } else529529- rc = -ENOMEM;530530- }440440+ rc = smk_set_access(rule, rule_list, rule_lock, load);441441+ if (rc == 0) {442442+ rc = count;531443 goto out;532444 }533445···18361774static ssize_t smk_user_access(struct file *file, const char __user *buf,18371775 size_t count, loff_t *ppos, int format)18381776{18391839- struct smack_rule rule;17771777+ struct smack_parsed_rule rule;18401778 char *data;18411779 char *cod;18421780 int res;···18581796 return -ENOMEM;18591797 memcpy(cod, data, count);18601798 cod[count] = '\0';18611861- res = smk_parse_long_rule(cod, &rule, 0);17991799+ res = smk_parse_long_rule(cod, &rule, 0, 0);18621800 kfree(cod);18631801 }1864180218651803 if (res)18661804 return -EINVAL;1867180518681868- res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access,18061806+ res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access1,18691807 NULL);18701808 data[0] = res == 0 ? '1' : '0';18711809 data[1] = '\0';···20972035 }2098203620992037 skp = smk_find_entry(cp);21002100- if (skp == NULL) {21012101- rc = -EINVAL;20382038+ if (skp == NULL)21022039 goto free_out;21032103- }2104204021052041 rule_list = &skp->smk_rules;21062042 rule_lock = &skp->smk_rules_lock;···21352075 return -ENOMEM;21362076 return 0;21372077}20782078+20792079+/**20802080+ * smk_write_change_rule - write() for /smack/change-rule20812081+ * @file: file pointer20822082+ * @buf: data from user space20832083+ * @count: bytes sent20842084+ * @ppos: where to start - must be 020852085+ */20862086+static ssize_t smk_write_change_rule(struct file *file, const char __user *buf,20872087+ size_t count, loff_t *ppos)20882088+{20892089+ /*20902090+ * Must have privilege.20912091+ */20922092+ if (!capable(CAP_MAC_ADMIN))20932093+ return -EPERM;20942094+20952095+ return smk_write_rules_list(file, buf, count, ppos, NULL, NULL,20962096+ SMK_CHANGE_FMT);20972097+}20982098+20992099+static const struct file_operations smk_change_rule_ops = {21002100+ .write = smk_write_change_rule,21012101+ .read = simple_transaction_read,21022102+ .release = simple_transaction_release,21032103+ .llseek = generic_file_llseek,21042104+};2138210521392106/**21402107 * smk_fill_super - fill the /smackfs superblock···22122125 [SMK_REVOKE_SUBJ] = {22132126 "revoke-subject", &smk_revoke_subj_ops,22142127 S_IRUGO|S_IWUSR},21282128+ [SMK_CHANGE_RULE] = {21292129+ "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},22152130 /* last one */22162131 {""}22172132 };