diff options
Diffstat (limited to 'backport/compat/backport-4.20.c')
-rw-r--r-- | backport/compat/backport-4.20.c | 379 |
1 files changed, 0 insertions, 379 deletions
diff --git a/backport/compat/backport-4.20.c b/backport/compat/backport-4.20.c deleted file mode 100644 index e26f3b52..00000000 --- a/backport/compat/backport-4.20.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (C) 2018 Intel Corporation - * - * Backport functionality introduced in Linux 4.20. - * This is basically upstream lib/nlattr.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/kernel.h> -#include <linux/export.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <net/netlink.h> - -static const u8 nla_attr_len[NLA_TYPE_MAX+1] = { - [NLA_U8] = sizeof(u8), - [NLA_U16] = sizeof(u16), - [NLA_U32] = sizeof(u32), - [NLA_U64] = sizeof(u64), - [NLA_S8] = sizeof(s8), - [NLA_S16] = sizeof(s16), - [NLA_S32] = sizeof(s32), - [NLA_S64] = sizeof(s64), -}; - -static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = { - [NLA_U8] = sizeof(u8), - [NLA_U16] = sizeof(u16), - [NLA_U32] = sizeof(u32), - [NLA_U64] = sizeof(u64), - [NLA_MSECS] = sizeof(u64), - [NLA_NESTED] = NLA_HDRLEN, - [NLA_S8] = sizeof(s8), - [NLA_S16] = sizeof(s16), - [NLA_S32] = sizeof(s32), - [NLA_S64] = sizeof(s64), -}; - -static int validate_nla_bitfield32(const struct nlattr *nla, - const u32 *valid_flags_mask) -{ - const struct nla_bitfield32 *bf = nla_data(nla); - - if (!valid_flags_mask) - return -EINVAL; - - /*disallow invalid bit selector */ - if (bf->selector & ~*valid_flags_mask) - return -EINVAL; - - /*disallow invalid bit values */ - if (bf->value & ~*valid_flags_mask) - return -EINVAL; - - /*disallow valid bit values that are not selected*/ - if (bf->value & ~bf->selector) - return -EINVAL; - - return 0; -} - -static int nla_validate_array(const struct nlattr *head, int len, int maxtype, - const struct nla_policy *policy, - struct netlink_ext_ack *extack) -{ - const struct nlattr *entry; - int rem; - - nla_for_each_attr(entry, head, len, rem) { - int ret; - - if (nla_len(entry) == 0) - continue; - - if (nla_len(entry) < NLA_HDRLEN) { - NL_SET_ERR_MSG_ATTR(extack, entry, - "Array element too short"); - return -ERANGE; - } - - ret = nla_validate(nla_data(entry), nla_len(entry), - maxtype, policy, extack); - if (ret < 0) - return ret; - } - - return 0; -} - -static int nla_validate_int_range(const struct nla_policy *pt, - const struct nlattr *nla, - struct netlink_ext_ack *extack) -{ - bool validate_min, validate_max; - s64 value; - - validate_min = pt->validation_type == NLA_VALIDATE_RANGE || - pt->validation_type == NLA_VALIDATE_MIN; - validate_max = pt->validation_type == NLA_VALIDATE_RANGE || - pt->validation_type == NLA_VALIDATE_MAX; - - switch (pt->type) { - case NLA_U8: - value = nla_get_u8(nla); - break; - case NLA_U16: - value = nla_get_u16(nla); - break; - case NLA_U32: - value = nla_get_u32(nla); - break; - case NLA_S8: - value = nla_get_s8(nla); - break; - case NLA_S16: - value = nla_get_s16(nla); - break; - case NLA_S32: - value = nla_get_s32(nla); - break; - case NLA_S64: - value = nla_get_s64(nla); - break; - case NLA_U64: - /* treat this one specially, since it may not fit into s64 */ - if ((validate_min && nla_get_u64(nla) < pt->min) || - (validate_max && nla_get_u64(nla) > pt->max)) { - NL_SET_ERR_MSG_ATTR(extack, nla, - "integer out of range"); - return -ERANGE; - } - return 0; - default: - WARN_ON(1); - return -EINVAL; - } - - if ((validate_min && value < pt->min) || - (validate_max && value > pt->max)) { - NL_SET_ERR_MSG_ATTR(extack, nla, - "integer out of range"); - return -ERANGE; - } - - return 0; -} - -static int validate_nla(const struct nlattr *nla, int maxtype, - const struct nla_policy *policy, - struct netlink_ext_ack *extack) -{ - const struct nla_policy *pt; - int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla); - int err = -ERANGE; - - if (type <= 0 || type > maxtype) - return 0; - - pt = &policy[type]; - - BUG_ON(pt->type > NLA_TYPE_MAX); - - if ((nla_attr_len[pt->type] && attrlen != nla_attr_len[pt->type]) || - (pt->type == NLA_EXACT_LEN_WARN && attrlen != pt->len)) { - pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.\n", - current->comm, type); - } - - switch (pt->type) { - case NLA_EXACT_LEN: - if (attrlen != pt->len) - goto out_err; - break; - - case NLA_REJECT: - if (extack && pt->validation_data) { - NL_SET_BAD_ATTR(extack, nla); - extack->_msg = pt->validation_data; - return -EINVAL; - } - err = -EINVAL; - goto out_err; - - case NLA_FLAG: - if (attrlen > 0) - goto out_err; - break; - - case NLA_BITFIELD32: - if (attrlen != sizeof(struct nla_bitfield32)) - goto out_err; - - err = validate_nla_bitfield32(nla, pt->validation_data); - if (err) - goto out_err; - break; - - case NLA_NUL_STRING: - if (pt->len) - minlen = min_t(int, attrlen, pt->len + 1); - else - minlen = attrlen; - - if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) { - err = -EINVAL; - goto out_err; - } - /* fall through */ - - case NLA_STRING: - if (attrlen < 1) - goto out_err; - - if (pt->len) { - char *buf = nla_data(nla); - - if (buf[attrlen - 1] == '\0') - attrlen--; - - if (attrlen > pt->len) - goto out_err; - } - break; - - case NLA_BINARY: - if (pt->len && attrlen > pt->len) - goto out_err; - break; - - case NLA_NESTED: - /* a nested attributes is allowed to be empty; if its not, - * it must have a size of at least NLA_HDRLEN. - */ - if (attrlen == 0) - break; - if (attrlen < NLA_HDRLEN) - goto out_err; - if (pt->validation_data) { - err = nla_validate(nla_data(nla), nla_len(nla), pt->len, - pt->validation_data, extack); - if (err < 0) { - /* - * return directly to preserve the inner - * error message/attribute pointer - */ - return err; - } - } - break; - case NLA_NESTED_ARRAY: - /* a nested array attribute is allowed to be empty; if its not, - * it must have a size of at least NLA_HDRLEN. - */ - if (attrlen == 0) - break; - if (attrlen < NLA_HDRLEN) - goto out_err; - if (pt->validation_data) { - int err; - - err = nla_validate_array(nla_data(nla), nla_len(nla), - pt->len, pt->validation_data, - extack); - if (err < 0) { - /* - * return directly to preserve the inner - * error message/attribute pointer - */ - return err; - } - } - break; - default: - if (pt->len) - minlen = pt->len; - else if (pt->type != NLA_UNSPEC) - minlen = nla_attr_minlen[pt->type]; - - if (attrlen < minlen) - goto out_err; - } - - /* further validation */ - switch (pt->validation_type) { - case NLA_VALIDATE_NONE: - /* nothing to do */ - break; - case NLA_VALIDATE_RANGE: - case NLA_VALIDATE_MIN: - case NLA_VALIDATE_MAX: - err = nla_validate_int_range(pt, nla, extack); - if (err) - return err; - break; - case NLA_VALIDATE_FUNCTION: - if (pt->validate) { - err = pt->validate(nla, extack); - if (err) - return err; - } - break; - } - - return 0; -out_err: - NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation"); - return err; -} - -int backport_nla_validate(const struct nlattr *head, int len, int maxtype, - const struct nla_policy *policy, - struct netlink_ext_ack *extack) -{ - const struct nlattr *nla; - int rem; - - nla_for_each_attr(nla, head, len, rem) { - int err = validate_nla(nla, maxtype, policy, extack); - - if (err < 0) - return err; - } - - return 0; -} -EXPORT_SYMBOL_GPL(backport_nla_validate); - -int backport_nla_policy_len(const struct nla_policy *p, int n) -{ - int i, len = 0; - - for (i = 0; i < n; i++, p++) { - if (p->len) - len += nla_total_size(p->len); - else if (nla_attr_len[p->type]) - len += nla_total_size(nla_attr_len[p->type]); - else if (nla_attr_minlen[p->type]) - len += nla_total_size(nla_attr_minlen[p->type]); - } - - return len; -} -EXPORT_SYMBOL_GPL(backport_nla_policy_len); - -int backport_nla_parse(struct nlattr **tb, int maxtype, - const struct nlattr *head, - int len, const struct nla_policy *policy, - struct netlink_ext_ack *extack) -{ - const struct nlattr *nla; - int rem; - - memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); - - nla_for_each_attr(nla, head, len, rem) { - u16 type = nla_type(nla); - - if (type > 0 && type <= maxtype) { - if (policy) { - int err = validate_nla(nla, maxtype, policy, - extack); - - if (err < 0) - return err; - } - - tb[type] = (struct nlattr *)nla; - } - } - - if (unlikely(rem > 0)) - pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n", - rem, current->comm); - - return 0; -} -EXPORT_SYMBOL(backport_nla_parse); |