diff --git a/parser/Makefile b/parser/Makefile index ca9c03ec8..add64b7e6 100644 --- a/parser/Makefile +++ b/parser/Makefile @@ -107,7 +107,7 @@ STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \ file_cache.h immunix.h lib.h mount.h network.h parser.h \ parser_include.h parser_version.h policy_cache.h policydb.h \ profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h \ - common_flags.h + common_flags.h bignum.h SPECIAL_HDRS = parser_yacc.h unit_test.h base_cap_names.h GENERATED_HDRS = af_names.h generated_af_names.h \ diff --git a/parser/bignum.h b/parser/bignum.h new file mode 100644 index 000000000..438294457 --- /dev/null +++ b/parser/bignum.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2023 + * Canonical Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ + +#ifndef __AA_BIGNUM_H +#define __AA_BIGNUM_H + +#include +#include +#include +#include +#include + +class bignum +{ +public: + std::vector data; + uint64_t sad = 543; + uint8_t base; + bool negative = false; + bignum () {} + + bignum (unsigned long val) { + if (val == 0) + data.push_back(val); + else { + while(val > 0) { + data.push_back(val % 10); + val /= 10; + } + } + base = 10; + } + + bignum (const char *val) { + while (*val) { + data.push_back(*val - 48); + val++; + } + std::reverse(data.begin(), data.end()); + base = 10; + } + + bignum (const uint8_t val[16]) { + size_t i; + bool flag = true; + for (i = 0; i < 16; i++) { + if ((val[i] & 0xF0) >> 4 != 0) + flag = false; + if (!flag) + data.push_back((val[i] & 0xF0) >> 4); + if ((val[i] & 0x0F) != 0) + flag = false; + if (!flag) + data.push_back(val[i] & 0x0F); + } + std::reverse(data.begin(), data.end()); + base = 16; + } + + bignum operator+(const bignum &brhs) const { + bignum b1 = this->size() < brhs.size() ? *this : brhs; + bignum b2 = this->size() < brhs.size() ? brhs : *this; + bignum result; + result.base = this->base; + uint8_t carryover = 0; + uint8_t sum; + size_t i; + for (i = 0; i < b1.size(); i++) { + sum = b1[i] + b2[i] + carryover; + if (sum > base - 1) + carryover = 1; + else + carryover = 0; + result.data.push_back(sum % base); + } + for (; i < b2.size(); i++) { + sum = b2[i] + carryover; + if (sum > base - 1) + carryover = 1; + else + carryover = 0; + result.data.push_back(sum % base); + } + if (carryover != 0) + result.data.push_back(carryover); + return result; + } + + bignum operator-(const bignum &brhs) const { + bignum b1 = this->size() < brhs.size() ? *this : brhs; + bignum b2 = this->size() < brhs.size() ? brhs : *this; + bignum result; + result.negative = *this < brhs; + result.base = this->base; + int8_t borrow = 0; + int8_t sub; + size_t i; + for (i = 0; i < b1.size(); i++) { + sub = b2[i] - b1[i] - borrow; + if (sub < 0) { + sub += base; + borrow = 1; + } else + borrow = 0; + result.data.push_back(sub); + } + for (; i < b2.size(); i++) { + sub = b2[i] - borrow; + if (sub < 0) { + sub += base; + borrow = 1; + } else + borrow = 0; + result.data.push_back(sub); + } + if (borrow) { + int8_t tmp = result.data[result.size() - 1] -= base; + tmp *= -1; + result.data[result.size() - 1] = tmp; + } + while (result.size() > 1 && result.data[result.size() - 1] == 0) + result.data.pop_back(); + + return result; + } + bool operator>=(const bignum &rhs) const { + return cmp_bignum(this->data, rhs.data) >= 0; + } + bool operator<=(const bignum &rhs) const { + return cmp_bignum(this->data, rhs.data) <= 0; + } + bool operator>(const bignum &rhs) const { + return cmp_bignum(this->data, rhs.data) > 0; + } + bool operator<(const bignum &rhs) const { + return cmp_bignum(this->data, rhs.data) < 0; + } + int operator[](int index) const { + return this->data[index]; + } + friend std::ostream &operator<<(std::ostream &os, bignum &bn); + size_t size() const { + return data.size(); + } + + /* + returns: + - 0, if the lhs and rhs are equal; + - a negative value if lhs is less than rhs; + - a positive value if lhs is greater than rhs. + */ + int cmp_bignum(std::vector lhs, std::vector rhs) const + { + if (lhs.size() > rhs.size()) + return 1; + else if (lhs.size() < rhs.size()) + return -1; + else { + /* assumes the digits are stored in reverse order */ + std::reverse(lhs.begin(), lhs.end()); + std::reverse(rhs.begin(), rhs.end()); + for (size_t i = 0; i < lhs.size(); i++) { + if (lhs[i] > rhs[i]) + return 1; + if (lhs[i] < rhs[i]) + return -1; + } + } + return 0; + } + + static bignum lower_bound_regex(bignum val) + { + /* single digit numbers reduce to 0 */ + if (val.size() == 1) { + val.data[0] = 0; + return val; + } + + for (auto& j : val.data) { + uint8_t tmp = j; + j = 0; + if (tmp != val.base - 1) { + break; + } + if (&j == &val.data[val.size()-2]) { + val.data[val.size()-1] = 1; + break; + } + } + return val; + + } + + static bignum upper_bound_regex(bignum val) + { + for (auto& j : val.data) { + uint8_t tmp = j; + j = val.base - 1; + if (tmp != 0) { + break; + } + } + return val; + } + +}; + +inline std::ostream &operator<<(std::ostream &os, bignum &bn) +{ + std::stringstream ss; + bignum tmp = bn; + std::reverse(tmp.data.begin(), tmp.data.end()); + for (auto i : tmp.data) + ss << std::hex << (int) i; + os << ss.str(); + return os; +}; + +#endif /* __AA_BIGNUM_H */ diff --git a/parser/parser.h b/parser/parser.h index 7cb89a139..d69db3ba0 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -37,6 +37,7 @@ #include "libapparmor_re/apparmor_re.h" #include "libapparmor_re/aare_rules.h" #include "rule.h" +#include "bignum.h" #include @@ -411,6 +412,7 @@ extern pattern_t convert_aaregex_to_pcre(const char *aare, int anchor, int glob, extern int build_list_val_expr(std::string& buffer, struct value_list *list); extern int convert_entry(std::string& buffer, char *entry); extern int clear_and_convert_entry(std::string& buffer, char *entry); +extern int convert_range(std::string& buffer, bignum start, bignum end); extern int process_regex(Profile *prof); extern int post_process_entry(struct cod_entry *entry); diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 380b0b138..7fb740e9d 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -845,6 +845,98 @@ int clear_and_convert_entry(std::string& buffer, char *entry) return convert_entry(buffer, entry); } +static std::vector> regex_range_generator(bignum start, bignum end) +{ + std::vector> forward; + std::vector> reverse; + bignum next, prev; + + while (start <= end) { + next = bignum::upper_bound_regex(start); + if (next > end) + break; + + forward.emplace_back(start, next); + start = next + 1; + } + + while (!end.negative && end >= start) { + prev = bignum::lower_bound_regex(end); + if (prev < start || prev.negative) + break; + + reverse.emplace_back(prev, end); + end = prev - 1; + } + + if (!end.negative && start <= end) { + forward.emplace_back(start, end); + } + + forward.insert(forward.end(), reverse.rbegin(), reverse.rend()); + return forward; +} + +static std::string generate_regex_range(bignum start, bignum end) +{ + std::ostringstream result; + std::vector> regex_range; + int j; + regex_range = regex_range_generator(start, end); + for (auto &i: regex_range) { + bignum sstart = i.first; + bignum send = i.second; + + for (j = sstart.size() - 1; j >= 0; j--) { + if (sstart[j] == send[j]) { + result << std::hex << sstart[j]; + } else { + if (sstart[j] < 10 && send[j] >= 10) { + result << '['; + result << std::hex << sstart[j]; + if (sstart[j] < 9) { + result << '-'; + result << '9'; + } + if (send[j] > 10) { + result << 'a'; + result << '-'; + } + result << std::hex << send[j]; + result << ']'; + } else { + result << '['; + result << std::hex << sstart[j]; + result << '-'; + result << std::hex << send[j]; + result << ']'; + } + } + } + if (&i != ®ex_range.back()) + result << ","; + } + return result.str(); +} + +int convert_range(std::string& buffer, bignum start, bignum end) +{ + pattern_t ptype; + int pos; + + std::string regex_range = generate_regex_range(start, end); + + if (!regex_range.empty()) { + ptype = convert_aaregex_to_pcre(regex_range.c_str(), 0, glob_default, buffer, &pos); + if (ptype == ePatternInvalid) + return FALSE; + } else { + buffer.append(default_match_pattern); + } + + return TRUE; +} + int post_process_policydb_ents(Profile *prof) { for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) {