flawopen.com/Teardowns/cve-2024-26642-linux-nftables-anonymous-set-timeout

● CVE-2024-26642 · CVSS 7.8 · उच्च
सुरक्षा अनुसंधान · FlawOpen

CVE-2024-26642: Linux nf_tables में टाइमआउट फ़्लैग वाला एनॉनिमस सेट

CVE-2024-26642 (NIST के अनुसार CVSS 7.8): nf_tables_newset() ऐसे एनॉनिमस सेट स्वीकार कर लेता था जिन पर टाइमआउट फ़्लैग भी लगा हो, जबकि कोई यूज़रस्पेस टूल यह जोड़ी नहीं बनाता; इससे किसी नियम से बँधे सेट एलिमेंट की समय-सीमा और गार्बेज कलेक्शन के दायरे में आ जाते थे। Linux 6.8 इसे -EOPNOTSUPP से ठुकरा देता है।

💡 आसान भाषा में (ELI5)

एक क्लोकरूम में दो व्यवस्थाएँ हैं। नंबर वाले हुक एक शाम के लिए सिर्फ़ एक मेहमान के होते हैं और मेहमान के जाते ही खाली कर दिए जाते हैं। समय वाली पर्चियों को एक कर्मचारी हर घंटे देखता है और जिनका समय पूरा हो गया उन्हें हटा देता है। फ़ॉर्म एक ही कोट के लिए दोनों खाने टिक करने देता है, तो वह हुक मेहमान के जाने पर भी खाली होता है और कर्मचारी के चक्कर पर भी। दो लोग मानते हैं कि वही हुक उनकी ज़िम्मेदारी है, और किसी को दूसरे का समय-सारणी नहीं पता। सुधार सीधा है: फ़ॉर्म अब यह जोड़ी स्वीकार नहीं करता।

इस पेज के मुख्य शब्द

nf_tables set
कर्नेल की डेटा संरचना जिसमें पते, पोर्ट या दूसरी कुंजियाँ होती हैं जिनसे nftables नियम मिलान करते हैं; यह NFT_MSG_NEWSET netlink संदेश से बनती है और nf_tables_newset() इसे संभालता है।
एनॉनिमस सेट (NFT_SET_ANONYMOUS)
बिना नाम का सेट, जैसे नियम के भीतर लिखा { 22, 80 }। यह उसी एक नियम से बँधा होता है और उसी ट्रांज़ैक्शन में नियम के साथ नष्ट होता है।
NFT_SET_TIMEOUT
वह फ़्लैग जो सेट के एलिमेंट को समाप्ति समय देता है। समय पूरा होने पर एलिमेंट सेट का गार्बेज कलेक्शन तंत्र हटाता है।
NFT_SET_EVAL
पैकेट पाथ से अपडेट होने वाले सेट का फ़्लैग, जिसे पुराने meter स्टेटमेंट इस्तेमाल करते हैं। सुधार उनके लिए एनॉनिमस + टाइमआउट + eval को अब भी वैध रखता है।
यूज़र नेमस्पेस में CAP_NET_ADMIN
nf_tables अपने नेटवर्क नेमस्पेस में CAP_NET_ADMIN रखने वाली किसी भी प्रोसेस का कॉन्फ़िगरेशन मान लेता है; जहाँ डिस्ट्रीब्यूशन अनुमति दे, वहाँ बिना विशेषाधिकार वाला उपयोगकर्ता यूज़र नेमस्पेस बनाकर यह पा सकता है।

मूल कारण विश्लेषण (Root Cause)

net/netfilter/nf_tables_api.c में nf_tables_newset() सेट फ़्लैग में सिर्फ़ अज्ञात बिट और MAP+OBJECT व EVAL+OBJECT टकराव जाँचता था। वह NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT स्वीकार कर लेता था, इसलिए जिस सेट का जीवनकाल एक ही नियम और ट्रांज़ैक्शन से बँधा है, उसमें ऐसे एलिमेंट भी हो सकते थे जिनकी समय-सीमा खत्म होती है और जिन्हें गार्बेज कलेक्शन उठाता है। यूज़रस्पेस यह जोड़ी कभी नहीं बनाता, और जीवनकाल संभालने वाला कोड इसके लिए नहीं लिखा गया था। अपस्ट्रीम सुधार इसे -EOPNOTSUPP से ठुकराता है, जब तक NFT_SET_EVAL भी सेट न हो। सार्वजनिक रिकॉर्ड इससे होने वाली मेमोरी त्रुटि का विस्तार नहीं देता; NIST इसे 7.8 (गोपनीयता, अखंडता और उपलब्धता तीनों उच्च) और कर्नेल CNA 5.5 (केवल उपलब्धता) अंक देता है।

हमले का चरण-दर-चरण प्रवाह

चरण 1

CAP_NET_ADMIN पाना

एक लोकल उपयोगकर्ता यूज़र नेमस्पेस और नेटवर्क नेमस्पेस बनाता है (जहाँ बिना विशेषाधिकार वाले यूज़र नेमस्पेस चालू हैं) और उस नेमस्पेस की nf_tables स्थिति पर CAP_NET_ADMIN पा लेता है।

चरण 2

अवैध सेट माँगना

एक netlink बैच में प्रोसेस NFTA_SET_FLAGS = NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT के साथ NFT_MSG_NEWSET भेजता है और lookup एक्सप्रेशन से सेट को एक नए नियम से बाँधता है।

चरण 3

कर्नेल स्वीकार कर लेता है

nf_tables_newset() को कोई वर्जित फ़्लैग जोड़ी नहीं मिलती और वह नियम से बँधा एक एनॉनिमस सेट बना देता है जिसके एलिमेंट की समय-सीमा होती है।

चरण 4

बिना परखे जीवनकाल पाथ

अब नियम को कमिट, एबॉर्ट या डिलीट करने पर सेट का विनाश और एलिमेंट का गार्बेज कलेक्शन एक साथ चलते हैं, ऐसे पाथ में जिन्हें nf_tables का ट्रांज़ैक्शन कोड सुरक्षित रूप से नहीं संभालता।

सोर्स कोड: कमज़ोर बनाम सुरक्षित कार्यान्वयन

कमज़ोर कार्यान्वयन
/* net/netfilter/nf_tables_api.c: nf_tables_newset(), before the fix */
	if (nla[NFTA_SET_FLAGS] != NULL) {
		flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
		if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
			      NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
			      NFT_SET_MAP | NFT_SET_EVAL |
			      NFT_SET_OBJECT | NFT_SET_CONCAT | NFT_SET_EXPR))
			return -EOPNOTSUPP;
		/* Only one of these operations is supported */
		if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
			     (NFT_SET_MAP | NFT_SET_OBJECT))
			return -EOPNOTSUPP;
		if ((flags & (NFT_SET_EVAL | NFT_SET_OBJECT)) ==
			     (NFT_SET_EVAL | NFT_SET_OBJECT))
			return -EOPNOTSUPP;
		/* BUG: NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT is accepted. A rule-bound
		 * anonymous set now also gets per-element expiry and garbage
		 * collection, a combination nft never creates and the set
		 * lifetime code was not written for. */
	}
सुरक्षित और सुदृढ़ फ़िक्स
/* net/netfilter/nf_tables_api.c: nf_tables_newset(), commit 16603605b667 */
	if (nla[NFTA_SET_FLAGS] != NULL) {
		flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
		if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
			      NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
			      NFT_SET_MAP | NFT_SET_EVAL |
			      NFT_SET_OBJECT | NFT_SET_CONCAT | NFT_SET_EXPR))
			return -EOPNOTSUPP;
		/* Only one of these operations is supported */
		if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
			     (NFT_SET_MAP | NFT_SET_OBJECT))
			return -EOPNOTSUPP;
		if ((flags & (NFT_SET_EVAL | NFT_SET_OBJECT)) ==
			     (NFT_SET_EVAL | NFT_SET_OBJECT))
			return -EOPNOTSUPP;
		/* FIX: anonymous sets are never used with timeouts from userspace,
		 * so reject the combination before the set exists. NFT_SET_EVAL
		 * stays allowed so legacy meters keep working. */
		if ((flags & (NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT | NFT_SET_EVAL)) ==
			     (NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT))
			return -EOPNOTSUPP;
	}

इंजीनियरिंग और सिस्टम सुरक्षा चेकलिस्ट

स्रोत