
Linux कर्नेल 1-दिन विश्लेषण और शोषण
nft_parse_register फ़ंक्शन में, जब arg डिफ़ॉल्ट रूप से पारित किया जाता है तो उसकी पुष्टि नहीं की जाती है, जिससे nft_do_chain फ़ंक्शन के स्टैक में OOB (बाउंड से बाहर) उत्पन्न होता है।
इस समय, payload एक्सप्रेशन का उपयोग करके read और write दोनों किया जा सकता है।
payload नीचे दिए गए अनुसार कार्य करता है।

अर्थात, इंडेक्स को उचित रूप से समायोजित करके स्टैक में OOB read और write किया जा सकता है।
लेकिन, regs के लिए एक सत्यापन फ़ंक्शन मौजूद है।
default:
if (reg < NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE)
return -EINVAL;
if (len == 0)
return -EINVAL;
if (reg * NFT_REG32_SIZE + len >
sizeof_field(struct nft_regs, data))
return -ERANGE;
if (data != NULL && type != NFT_DATA_VALUE)
return -EINVAL;
return 0;
उपरोक्त कोड को देखते हुए, reg * NFT_REG32_SIZE + len > sizeof_field(struct nft_regs, data) को संतुष्ट करना होगा।
स्थिरांक डालने पर, reg * 4 + len > 80 इसे संतुष्ट करना होगा।
अर्थात, reg के अनुसार len को उचित रूप से समायोजित करना होगा।
nft_regs
struct nft_regs {
union {
u32 data[20];
struct nft_verdict verdict;
};
};
nft_do_chain
unsigned int
nft_do_chain(struct nft_pktinfo *pkt, void *priv)
{
const struct nft_chain *chain = priv, *basechain = chain;
const struct net *net = nft_net(pkt);
struct nft_rule *const *rules;
const struct nft_rule *rule;
const struct nft_expr *expr, *last;
struct nft_regs regs;
...
}
nft_parse_register
static unsigned int nft_parse_register(const struct nlattr *attr)
{
unsigned int reg;
reg = ntohl(nla_get_be32(attr));
switch (reg) {
case NFT_REG_VERDICT...NFT_REG_4:
return reg * NFT_REG_SIZE / NFT_REG32_SIZE;
default:
return reg + NFT_REG_SIZE / NFT_REG32_SIZE - NFT_REG32_00;
}
}