^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Casey Schaufler <casey@schaufler-ca.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "smack.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) struct smack_known smack_known_huh = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) .smk_known = "?",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) .smk_secid = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct smack_known smack_known_hat = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) .smk_known = "^",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) .smk_secid = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct smack_known smack_known_star = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) .smk_known = "*",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) .smk_secid = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct smack_known smack_known_floor = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) .smk_known = "_",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) .smk_secid = 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct smack_known smack_known_web = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .smk_known = "@",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) .smk_secid = 7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) LIST_HEAD(smack_known_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * The initial value needs to be bigger than any of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * known values above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static u32 smack_next_secid = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * what events do we log
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * can be overwritten at run-time by /smack/logging
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int log_policy = SMACK_AUDIT_DENIED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * smk_access_entry - look up matching access rule
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * @subject_label: a pointer to the subject's Smack label
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * @object_label: a pointer to the object's Smack label
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * @rule_list: the list of rules to search
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * This function looks up the subject/object pair in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * access rule list and returns the access mode. If no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * entry is found returns -ENOENT.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * NOTE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * Earlier versions of this function allowed for labels that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * were not on the label list. This was done to allow for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * labels to come over the network that had never been seen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * before on this host. Unless the receiving socket has the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * star label this will always result in a failure check. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * star labeled socket case is now handled in the networking
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * hooks so there is no case where the label is not on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * label list. Checking to see if the address of two labels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * is the same is now a reliable test.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * Do the object check first because that is more
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * likely to differ.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * Allowing write access implies allowing locking.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) int smk_access_entry(char *subject_label, char *object_label,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct list_head *rule_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct smack_rule *srp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) list_for_each_entry_rcu(srp, rule_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (srp->smk_object->smk_known == object_label &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) srp->smk_subject->smk_known == subject_label) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int may = srp->smk_access;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * MAY_WRITE implies MAY_LOCK.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if ((may & MAY_WRITE) == MAY_WRITE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) may |= MAY_LOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return may;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * smk_access - determine if a subject has a specific access to an object
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * @subject: a pointer to the subject's Smack label entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * @object: a pointer to the object's Smack label entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * @request: the access requested, in "MAY" format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * @a : a pointer to the audit data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * This function looks up the subject/object pair in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * access rule list and returns 0 if the access is permitted,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * non zero otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * Smack labels are shared on smack_list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) int smk_access(struct smack_known *subject, struct smack_known *object,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int request, struct smk_audit_info *a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) int may = MAY_NOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * Hardcoded comparisons.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * A star subject can't access any object.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (subject == &smack_known_star) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) rc = -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) goto out_audit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * An internet object can be accessed by any subject.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * Tasks cannot be assigned the internet label.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * An internet subject can access any object.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (object == &smack_known_web || subject == &smack_known_web)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) goto out_audit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * A star object can be accessed by any subject.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (object == &smack_known_star)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) goto out_audit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * An object can be accessed in any way by a subject
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * with the same label.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (subject->smk_known == object->smk_known)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) goto out_audit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * A hat subject can read or lock any object.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * A floor object can be read or locked by any subject.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if ((request & MAY_ANYREAD) == request ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) (request & MAY_LOCK) == request) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (object == &smack_known_floor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) goto out_audit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (subject == &smack_known_hat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) goto out_audit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * Beyond here an explicit relationship is required.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * If the requested access is contained in the available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * access (e.g. read is included in readwrite) it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * good. A negative response from smk_access_entry()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * indicates there is no entry for this pair.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) may = smk_access_entry(subject->smk_known, object->smk_known,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) &subject->smk_rules);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (may <= 0 || (request & may) != request) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) rc = -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) goto out_audit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) #ifdef CONFIG_SECURITY_SMACK_BRINGUP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * Return a positive value if using bringup mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * This allows the hooks to identify checks that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * succeed because of "b" rules.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (may & MAY_BRINGUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) rc = SMACK_BRINGUP_ALLOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) out_audit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) #ifdef CONFIG_SECURITY_SMACK_BRINGUP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (object == smack_unconfined)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) rc = SMACK_UNCONFINED_OBJECT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (subject == smack_unconfined)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) rc = SMACK_UNCONFINED_SUBJECT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) #ifdef CONFIG_AUDIT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) smack_log(subject->smk_known, object->smk_known,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) request, rc, a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * smk_tskacc - determine if a task has a specific access to an object
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * @tsp: a pointer to the subject's task
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * @obj_known: a pointer to the object's label entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * @mode: the access requested, in "MAY" format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * @a : common audit data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * This function checks the subject task's label/object label pair
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * in the access rule list and returns 0 if the access is permitted,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * non zero otherwise. It allows that the task may have the capability
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * to override the rules.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) u32 mode, struct smk_audit_info *a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) struct smack_known *sbj_known = smk_of_task(tsp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) int may;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * Check the global rule list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) rc = smk_access(sbj_known, obj_known, mode, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (rc >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) * If there is an entry in the task's rule list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * it can further restrict access.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) may = smk_access_entry(sbj_known->smk_known,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) obj_known->smk_known,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) &tsp->smk_rules);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (may < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) goto out_audit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if ((mode & may) == mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) goto out_audit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) rc = -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * Allow for priviliged to override policy.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) out_audit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) #ifdef CONFIG_AUDIT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) smack_log(sbj_known->smk_known, obj_known->smk_known,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) mode, rc, a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * smk_curacc - determine if current has a specific access to an object
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * @obj_known: a pointer to the object's Smack label entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * @mode: the access requested, in "MAY" format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * @a : common audit data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) * This function checks the current subject label/object label pair
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * in the access rule list and returns 0 if the access is permitted,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) * non zero otherwise. It allows that current may have the capability
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * to override the rules.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int smk_curacc(struct smack_known *obj_known,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) u32 mode, struct smk_audit_info *a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) struct task_smack *tsp = smack_cred(current_cred());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return smk_tskacc(tsp, obj_known, mode, a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) #ifdef CONFIG_AUDIT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * smack_str_from_perm : helper to transalate an int to a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) * readable string
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * @string : the string to fill
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * @access : the int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) static inline void smack_str_from_perm(char *string, int access)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (access & MAY_READ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) string[i++] = 'r';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (access & MAY_WRITE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) string[i++] = 'w';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (access & MAY_EXEC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) string[i++] = 'x';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (access & MAY_APPEND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) string[i++] = 'a';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (access & MAY_TRANSMUTE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) string[i++] = 't';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (access & MAY_LOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) string[i++] = 'l';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) string[i] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) * smack_log_callback - SMACK specific information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) * will be called by generic audit code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) * @ab : the audit_buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * @a : audit_data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) static void smack_log_callback(struct audit_buffer *ab, void *a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) struct common_audit_data *ad = a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) struct smack_audit_data *sad = ad->smack_audit_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) ad->smack_audit_data->function,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) sad->result ? "denied" : "granted");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) audit_log_format(ab, " subject=");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) audit_log_untrustedstring(ab, sad->subject);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) audit_log_format(ab, " object=");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) audit_log_untrustedstring(ab, sad->object);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (sad->request[0] == '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) audit_log_format(ab, " labels_differ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) audit_log_format(ab, " requested=%s", sad->request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) * smack_log - Audit the granting or denial of permissions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * @subject_label : smack label of the requester
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) * @object_label : smack label of the object being accessed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) * @request: requested permissions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) * @result: result from smk_access
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) * @a: auxiliary audit data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) * Audit the granting or denial of permissions in accordance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) * with the policy.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) void smack_log(char *subject_label, char *object_label, int request,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) int result, struct smk_audit_info *ad)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) #ifdef CONFIG_SECURITY_SMACK_BRINGUP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) char request_buffer[SMK_NUM_ACCESS_TYPE + 5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) struct smack_audit_data *sad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct common_audit_data *a = &ad->a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) /* check if we have to log the current event */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (result < 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) sad = a->smack_audit_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (sad->function == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) sad->function = "unknown";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) /* end preparing the audit data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) smack_str_from_perm(request_buffer, request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) sad->subject = subject_label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) sad->object = object_label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) #ifdef CONFIG_SECURITY_SMACK_BRINGUP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * The result may be positive in bringup mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * A positive result is an allow, but not for normal reasons.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) * Mark it as successful, but don't filter it out even if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * the logging policy says to do so.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (result == SMACK_UNCONFINED_SUBJECT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) strcat(request_buffer, "(US)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) else if (result == SMACK_UNCONFINED_OBJECT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) strcat(request_buffer, "(UO)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (result > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) sad->request = request_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) sad->result = result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) common_lsm_audit(a, smack_log_callback, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) #else /* #ifdef CONFIG_AUDIT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) void smack_log(char *subject_label, char *object_label, int request,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) int result, struct smk_audit_info *ad)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) DEFINE_MUTEX(smack_known_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * smk_insert_entry - insert a smack label into a hash map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) * this function must be called under smack_known_lock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) void smk_insert_entry(struct smack_known *skp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) unsigned int hash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct hlist_head *head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) hash = full_name_hash(NULL, skp->smk_known, strlen(skp->smk_known));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) hlist_add_head_rcu(&skp->smk_hashed, head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) list_add_rcu(&skp->list, &smack_known_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) * smk_find_entry - find a label on the list, return the list entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * @string: a text string that might be a Smack label
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) * Returns a pointer to the entry in the label list that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) * matches the passed string or NULL if not found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) struct smack_known *smk_find_entry(const char *string)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) unsigned int hash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) struct hlist_head *head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) struct smack_known *skp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) hash = full_name_hash(NULL, string, strlen(string));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) hlist_for_each_entry_rcu(skp, head, smk_hashed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) if (strcmp(skp->smk_known, string) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) return skp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * smk_parse_smack - parse smack label from a text string
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * @string: a text string that might contain a Smack label
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * @len: the maximum size, or zero if it is NULL terminated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) * Returns a pointer to the clean label or an error code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) char *smk_parse_smack(const char *string, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) char *smack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) if (len <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) len = strlen(string) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * Reserve a leading '-' as an indicator that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * this isn't a label, but an option to interfaces
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * including /smack/cipso and /smack/cipso2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) if (string[0] == '-')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) for (i = 0; i < len; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) string[i] == '"' || string[i] == '\\' || string[i] == '\'')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (i == 0 || i >= SMK_LONGLABEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) smack = kzalloc(i + 1, GFP_NOFS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (smack == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) strncpy(smack, string, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return smack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) * smk_netlbl_mls - convert a catset to netlabel mls categories
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) * @catset: the Smack categories
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) * @sap: where to put the netlabel categories
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) * Allocates and fills attr.mls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) * Returns 0 on success, error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) unsigned char *cp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) unsigned char m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) int cat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) int byte;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) sap->flags |= NETLBL_SECATTR_MLS_CAT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) sap->attr.mls.lvl = level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) sap->attr.mls.cat = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) for (m = 0x80; m != 0; m >>= 1, cat++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if ((m & *cp) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) rc = netlbl_catmap_setbit(&sap->attr.mls.cat,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) cat, GFP_NOFS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) netlbl_catmap_free(sap->attr.mls.cat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) * smack_populate_secattr - fill in the smack_known netlabel information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * @skp: pointer to the structure to fill
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) * Populate the netlabel secattr structure for a Smack label.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) * Returns 0 unless creating the category mapping fails
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) int smack_populate_secattr(struct smack_known *skp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) int slen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) skp->smk_netlabel.attr.secid = skp->smk_secid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) skp->smk_netlabel.domain = skp->smk_known;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) skp->smk_netlabel.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if (skp->smk_netlabel.cache != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) skp->smk_netlabel.flags |= NETLBL_SECATTR_CACHE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) skp->smk_netlabel.cache->free = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) skp->smk_netlabel.cache->data = skp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) skp->smk_netlabel.flags |= NETLBL_SECATTR_SECID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) NETLBL_SECATTR_MLS_LVL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) NETLBL_SECATTR_DOMAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) * If direct labeling works use it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * Otherwise use mapped labeling.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) slen = strlen(skp->smk_known);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (slen < SMK_CIPSOLEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) return smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) &skp->smk_netlabel, slen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) return smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) &skp->smk_netlabel, sizeof(skp->smk_secid));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) * smk_import_entry - import a label, return the list entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) * @string: a text string that might be a Smack label
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) * @len: the maximum size, or zero if it is NULL terminated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) * Returns a pointer to the entry in the label list that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * matches the passed string, adding it if necessary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * or an error code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) struct smack_known *smk_import_entry(const char *string, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) struct smack_known *skp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) char *smack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) smack = smk_parse_smack(string, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (IS_ERR(smack))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) return ERR_CAST(smack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) mutex_lock(&smack_known_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) skp = smk_find_entry(smack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) if (skp != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) goto freeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) skp = kzalloc(sizeof(*skp), GFP_NOFS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (skp == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) skp = ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) goto freeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) skp->smk_known = smack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) skp->smk_secid = smack_next_secid++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) rc = smack_populate_secattr(skp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (rc >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) INIT_LIST_HEAD(&skp->smk_rules);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) mutex_init(&skp->smk_rules_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) * Make sure that the entry is actually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) * filled before putting it on the list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) smk_insert_entry(skp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) goto unlockout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) kfree(skp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) skp = ERR_PTR(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) freeout:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) kfree(smack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) unlockout:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) mutex_unlock(&smack_known_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) return skp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) * smack_from_secid - find the Smack label associated with a secid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) * @secid: an integer that might be associated with a Smack label
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) * Returns a pointer to the appropriate Smack label entry if there is one,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) * otherwise a pointer to the invalid Smack label.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) struct smack_known *smack_from_secid(const u32 secid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) struct smack_known *skp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) list_for_each_entry_rcu(skp, &smack_known_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) if (skp->smk_secid == secid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return skp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * If we got this far someone asked for the translation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) * of a secid that is not on the list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) return &smack_known_huh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * Unless a process is running with one of these labels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) * even having CAP_MAC_OVERRIDE isn't enough to grant
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) * privilege to violate MAC policy. If no labels are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) * designated (the empty list case) capabilities apply to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) * everyone.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) LIST_HEAD(smack_onlycap_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) DEFINE_MUTEX(smack_onlycap_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) * smack_privileged_cred - are all privilege requirements met by cred
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) * @cap: The requested capability
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) * @cred: the credential to use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) * Is the task privileged and allowed to be privileged
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) * by the onlycap rule.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) * Returns true if the task is allowed to be privileged, false if it's not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) bool smack_privileged_cred(int cap, const struct cred *cred)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) struct task_smack *tsp = smack_cred(cred);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) struct smack_known *skp = tsp->smk_task;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) struct smack_known_list_elem *sklep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) if (list_empty(&smack_onlycap_list)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (sklep->smk_label == skp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) * smack_privileged - are all privilege requirements met
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) * @cap: The requested capability
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) * Is the task privileged and allowed to be privileged
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) * by the onlycap rule.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * Returns true if the task is allowed to be privileged, false if it's not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) bool smack_privileged(int cap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) * Kernel threads may not have credentials we can use.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * The io_uring kernel threads do have reliable credentials.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) if ((current->flags & (PF_KTHREAD | PF_IO_WORKER)) == PF_KTHREAD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) return smack_privileged_cred(cap, current_cred());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) }