
تحليل واستغلال ثغرات 1-Day في Linux Kernel
نظرًا لعدم وجود تحقق عند تمرير arg إلى الحالة الافتراضية في دالة nft_parse_register، يحدث تجاوز للحدود (oob) في مكدس دالة nft_do_chain.
في هذه الحالة، باستخدام تعبير الحمولة (payload expression) يمكن إجراء القراءة والكتابة معًا.
تعمل الحمولة (payload) على النحو التالي:

أي أنه بضبط المؤشر (index) بشكل مناسب، يمكن إجراء قراءة وكتابة خارج الحدود (oob) في المكدس.
لكن توجد دالة تقوم بالتحقق من صحة 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.
أي يجب ضبط len بشكل مناسب وفقًا لـ reg.
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;
}
}