
Docker mitigation for CVE-2026-31431 ('Copy Fail') के लिए शमन उपाय। इसमें Kubernetes टेम्पलेट भी शामिल हैं।
सभी Docker कंटेनरों के लिए AF_ALG सॉकेट निर्माण को ब्लॉक करने के लिए इडेम्पोटेंट स्क्रिप्ट, जो CVE-2026-31431 ("Copy Fail") के शमन के रूप में होस्ट पर चलती है।
CVE-2026-31431 Linux कर्नेल के authencesn क्रिप्टोग्राफिक टेम्पलेट में एक स्थानीय विशेषाधिकार वृद्धि है, जो 2017 और अपस्ट्रीम फिक्स (मेनलाइन कमिट a664bf3d603d) की उपलब्धता के बीच निर्मित कर्नेल में मौजूद है। एक अन-प्रिविलेज्ड उपयोगकर्ता AF_ALG सॉकेट ऑपरेशन को splice() के साथ जोड़कर किसी भी पठनीय फ़ाइल के पेज कैश में नियंत्रित 4-बाइट लेखन कर सकता है, जिससे setuid बाइनरी को लक्षित करके रूट शेल प्राप्त किया जा सकता है। एक 732-बाइट Python प्रूफ ऑफ कॉन्सेप्ट इसे बिना रेस या प्रति-डिस्ट्रो ऑफसेट के, प्रभावित कर्नेल वितरित करने वाले हर प्रमुख Linux वितरण पर विश्वसनीय रूप से शोषित करता है।
एक्सप्लॉइट का अनिवार्य पहला चरण AF_ALG सॉकेट खोलना है (socket(AF_ALG, SOCK_SEQPACKET, 0))। seccomp के माध्यम से उस syscall को ब्लॉक करना अनपैच्ड कर्नेल पर भी शोषण को रोकता है। Docker का अंतर्निहित डिफ़ॉल्ट seccomp प्रोफ़ाइल को ब्लॉक नहीं करता है, और पर्याप्त नहीं है — परीक्षण किए गए क्लस्टरों ने दिखाया कि PSS Restricted के तहत स्वीकार किए गए पॉड अभी भी सॉकेट खोल सकते हैं।
AF_ALGRuntimeDefaultAF_ALGपूर्ण तकनीकी विवरण और वितरण द्वारा पैच उपलब्धता के लिए मूल शोधकर्ता सलाह https://copy.fail और CERT-EU सलाह https://cert.europa.eu/publications/security-advisories/2026-005/ देखें।
यह स्क्रिप्ट Docker Engine के वैश्विक डेमन कॉन्फ़िगरेशन को कवर करती है। Kubernetes के लिए, नीचे Kubernetes अनुभाग देखें। बेयर-मेटल या VM वर्कलोड (गैर-कंटेनरीकृत) के लिए, इसके बजाय algif_aead कर्नेल मॉड्यूल को अक्षम करें:
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true
उस दृष्टिकोण का dm-crypt/LUKS, kTLS, IPsec/XFRM, OpenSSL, GnuTLS, NSS, या SSH पर कोई प्रभाव नहीं पड़ता है।
Docker के सक्रिय अंतर्निहित seccomp प्रोफ़ाइल को निकालता है एक अल्पकालिक कंटेनर के HostConfig.SecurityOpt का निरीक्षण करके। यह किसी दूरस्थ URL पर किसी भी निर्भरता से बचता है और गारंटी देता है कि आधार प्रोफ़ाइल वास्तव में स्थापित Docker संस्करण से मेल खाती है। moby/profiles से GitHub फ़ेच केवल फ़ॉलबैक के रूप में उपयोग किया जाता है यदि कंटेनर निरीक्षण से कुछ नहीं मिलता है।
प्रोफ़ाइल को पैच करता है Docker की अनुमति सूची प्रविष्टि से socket को हटाकर और इसे एक तर्क फ़िल्टर के साथ फिर से जोड़कर जो AF_ALG (मान 38) को छोड़कर सभी एड्रेस फ़ैमिली की अनुमति देता है, SCMP_CMP_NE का उपयोग करके। अन्य सभी Docker डिफ़ॉल्ट seccomp व्यवहार संरक्षित है।
पैच किए गए प्रोफ़ाइल को परमाणु रूप से लिखता है /etc/seccomp/docker-block-af-alg.json पर (अस्थायी फ़ाइल + rename)। यदि डिस्क पर मौजूद सामग्री पहले से समान है तो छोड़ दिया जाता है।
/etc/docker/daemon.json को अपडेट करता है ताकि "seccomp-profile" को पैच किए गए प्रोफ़ाइल पथ पर सेट किया जा सके। पहले संशोधन पर मूल फ़ाइल का बैकअप daemon.json.bak में लिया जाता है। यदि पहले से सही ढंग से कॉन्फ़िगर किया गया है तो छोड़ दिया जाता है।
dockerd को रीलोड करता है systemctl reload docker के माध्यम से (SIGHUP — कोई पुनरारंभ आवश्यक नहीं)। यदि कोई भी फ़ाइल नहीं बदली है तो छोड़ दिया जाता है।
ब्लॉक के सक्रिय होने की पुष्टि करता है एक कंटेनर के अंदर एक प्रोब चलाकर, भले ही उपरोक्त चरणों में कोई परिवर्तन किया गया हो या नहीं।
स्क्रिप्ट इडेम्पोटेंट है: इसे कई बार चलाने से समान परिणाम मिलता है और केवल तभी Docker को रीलोड करता है जब वास्तव में कुछ बदला गया हो।
नोट:
--privilegedकंटेनर इस कॉन्फ़िगरेशन की परवाह किए बिना सभी seccomp प्रोफ़ाइल को बायपास करते हैं। अपनी Compose फ़ाइलों का ऑडिट करें और प्रिविलेज्ड कंटेनरों के लिए कमांड अलग से चलाएं।
PATH में docker CLIPATH में curl (केवल फ़ॉलबैक)systemctl (systemd होस्ट)/etc/seccomp और /etc/docker में लेखन के लिए रूट / sudo, और systemctl reload docker के लिए# शमन लागू करें और सत्यापित करें (सामान्य उपयोग)
sudo python3 harden-docker-seccomp.py
# कुछ भी लिखे या Docker को रीलोड किए बिना दिखाएं कि क्या बदलेगा
sudo python3 harden-docker-seccomp.py --dry-run
# केवल कंटेनर सत्यापन फिर से चलाएं (कोई कॉन्फ़िग परिवर्तन नहीं)
python3 harden-docker-seccomp.py --verify-only
# विस्तृत आउटपुट
sudo python3 harden-docker-seccomp.py --verbose
INFO Written: /etc/seccomp/docker-block-af-alg.json
INFO Updated: /etc/docker/daemon.json
INFO Reloading Docker daemon (SIGHUP)…
INFO Docker daemon reloaded.
INFO Verifying AF_ALG is blocked inside a container…
OK: AF_ALG blocked — [Errno 1] Operation not permitted
INFO All done. CVE-2026-31431 (Copy Fail) mitigation is active.
INFO Profile unchanged: /etc/seccomp/docker-block-af-alg.json
INFO daemon.json already configured correctly.
INFO No changes — Docker daemon reload not required.
INFO Verifying AF_ALG is blocked inside a container…
OK: AF_ALG blocked — [Errno 1] Operation not permitted
INFO All done. CVE-2026-31431 (Copy Fail) mitigation is active.
| कोड | अर्थ |
|---|---|
0 | सफलता — शमन सक्रिय है |
1 | स्क्रिप्ट रूट के रूप में नहीं चलाई गई (पैचिंग करते समय), या अपरिवर्तनीय त्रुटि |
2 | सत्यापन विफल — AF_ALG ब्लॉक नहीं है |
Kubernetes पॉड होस्ट कर्नेल साझा करते हैं, इसलिए वही AF_ALG सॉकेट प्रिमिटिव प्रभावित नोड पर किसी भी पॉड से पहुंच योग्य है। RuntimeDefault seccomp पर्याप्त नहीं है — परीक्षण किए गए क्लस्टरों ने दिखाया कि PSS Restricted के तहत स्वीकार किए गए पॉड अभी भी AF_ALG सॉकेट खोल सकते हैं। स्पष्ट अस्वीकृति नियम के साथ एक Localhost प्रोफ़ाइल आवश्यक है।
शमन के लिए दो चीजों की आवश्यकता होती है: प्रोफ़ाइल JSON हर नोड के फ़ाइल सिस्टम पर मौजूद होना, और हर पॉड स्पेक उसका संदर्भ देना। नीचे दिए गए अनुभाग दोनों को कवर करते हैं, जिसमें व्यक्तिगत पॉड स्पेक को संशोधित किए बिना प्रोफ़ाइल को वैश्विक रूप से इंजेक्ट करने का तरीका भी शामिल है।
kubelet Localhost seccomp प्रोफ़ाइल को अपने seccomp रूट के सापेक्ष हल करता है, जो डिफ़ॉल्ट रूप से /var/lib/kubelet/seccomp है। प्रोफ़ाइल उस पथ पर हर नोड पर मौजूद होनी चाहिए जो वर्कलोड शेड्यूल कर सकता है।
इस रिपॉजिटरी से ConfigMap और DaemonSet लागू करें:
kubectl apply -f templates/configmap-seccomp-profile.yaml
kubectl apply -f templates/daemonset-distribute-profile.yaml
DaemonSet एक init कंटेनर चलाता है जो प्रोफ़ाइल को ConfigMap से नोड के kubelet seccomp रूट में कॉपी करता है, फिर एक न्यूनतम pause कंटेनर पार्क करता है ताकि पॉड स्वास्थ्य निगरानी के लिए दृश्यमान रहे। यह सभी टेंट्स को सहन करता है ताकि यह कंट्रोल-प्लेन नोड्स पर भी चले।
गैर-मानक kubelet seccomp रूट: RKE2
/var/lib/rancher/rke2/agent/kubelet/seccompका उपयोग करता है। लागू करने से पहले DaemonSet के init कंटेनर env मेंNODE_SECCOMP_ROOTसेट करके पथ को ओवरराइड करें।
किसी नोड पर फ़ाइल की उपस्थिति सत्यापित करें:
kubectl -n kube-system exec -it \
$(kubectl -n kube-system get pod -l app.kubernetes.io/name=distribute-af-alg-seccomp \
-o jsonpath='{.items[0].metadata.name}') -- \
cat /var/lib/kubelet/seccomp/block-af-alg.json
व्यक्तिगत पॉड स्पेक या Helm चार्ट को संशोधित करने के बजाय, प्रवेश समय पर seccompProfile को स्वचालित रूप से इंजेक्ट करने के लिए एक म्यूटेटिंग एडमिशन वेबहुक का उपयोग करें। दो विकल्प प्रदान किए गए हैं: Kyverno और OPA Gatekeeper।
दोनों दृष्टिकोण केवल तभी प्रोफ़ाइल इंजेक्ट करते हैं जब पॉड पहले से एक घोषित नहीं करता है, इसलिए स्पष्ट प्रोफ़ाइल वाले पॉड अछूते रहते हैं।
महत्वपूर्ण: मौजूदा चल रहे पॉड पूर्वव्यापी रूप से म्यूटेट नहीं होते हैं। नीति लागू करने के बाद, इंजेक्ट की गई प्रोफ़ाइल को लेने के लिए अपने डिप्लॉयमेंट को रोल करें:
kubectl rollout restart deployment -A
यह टेम्पलेट MutatingPolicy API (policies.kyverno.io/v1) का उपयोग करता है, जो Kyverno 1.17 में GA तक पहुंच गया। लीगेसी ClusterPolicy API (kyverno.io/v1) को Kyverno 1.17 (जनवरी 2026) में हटा दिया गया था और 1.20 (अक्टूबर 2026) में हटाने की योजना है; नई नीतियों के लिए इसका उपयोग न करें।
matchConditions CEL अभिव्यक्ति जांचती है कि म्यूटेट करने से पहले seccompProfile अनुपस्थित है, इसलिए पहले से प्रोफ़ाइल घोषित करने वाले पॉड अछूते रहते हैं।
# Kyverno स्थापित करें (यदि पहले से मौजूद नहीं है)
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm upgrade --install kyverno kyverno/kyverno -n kyverno --create-namespace
# नीति लागू करें
kubectl apply -f templates/kyverno-mutate-seccomp.yaml
सत्यापित करें कि एक नया पॉड इंजेक्ट की गई प्रोफ़ाइल प्राप्त करता है:
kubectl run test --image=busybox --restart=Never -- sleep 30
kubectl get pod test -o jsonpath='{.spec.securityContext.seccompProfile}'
# अपेक्षित: {"localhostProfile":"block-af-alg.json","type":"Localhost"}
kubectl delete pod test
Gatekeeper का Assign म्यूटेशन CRD एक pathTests स्थिति का उपयोग करता है ताकि प्रोफ़ाइल केवल तभी इंजेक्ट की जाए जब spec.securityContext.seccompProfile पहले से मौजूद न हो। म्यूटेशन Gatekeeper 3.10+ से स्थिर है; कोई फीचर फ्लैग आवश्यक नहीं है।
# Gatekeeper स्थापित करें (यदि पहले से मौजूद नहीं है)
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper \
--create-namespace
# म्यूटेशन लागू करें
kubectl apply -f templates/gatekeeper-assign-seccomp.yaml
सत्यापित करें:
kubectl run test --image=busybox --restart=Never -- sleep 30
kubectl get pod test -o jsonpath='{.spec.securityContext.seccompProfile}'
# अपेक्षित: {"localhostProfile":"block-af-alg.json","type":"Localhost"}
kubectl delete pod test
Gatekeeper बनाम Kyverno:
Assignदृष्टिकोण फ़ील्ड स्तर पर काम करता है और Gatekeeper म्यूटेशन वेबहुक को सक्षम करने की आवश्यकता होती है। Kyverno काMutatingPolicyCELmatchConditionके साथ सशर्त को इनलाइन संभालता है। दोनों समान परिणाम प्राप्त करते हैं — जो भी आपके क्लस्टर में पहले से तैनात है उसे प्राथमिकता दें।
hostPID: true, hostNetwork: true, या securityContext.privileged: true वाले पॉड में उन्नत पहुंच होती है जिसे seccomp अकेले पूरी तरह से नियंत्रित नहीं कर सकता। उन वर्कलोड का अलग से ऑडिट करें और जहां संभव हो विशेषाधिकार हटाएं।
ConfigMap सत्य के स्रोत के रूप में। प्रोफ़ाइल JSON configmap-seccomp-profile.yaml में रहता है, न कि DaemonSet में एम्बेडेड या फ़ाइलों में डुप्लिकेट। DaemonSet इसे माउंट करता है और नोड पर कॉपी करता है। प्रोफ़ाइल को अपडेट करने का मतलब है एक ConfigMap संपादित करना और DaemonSet पॉड को पुनरारंभ करना — कोई अन्य फ़ाइल नहीं बदलती।
DaemonSet system-node-critical प्राथमिकता का उपयोग करता है। यह सुनिश्चित करता है कि वितरण पॉड को उन वर्कलोड से पहले बेदखल नहीं किया जाता है जिनकी यह सुरक्षा करता है, जो नोड्स को लापता प्रोफ़ाइल फ़ाइल और पॉड को CreateContainerError में फंसा सकता है।
Gatekeeper kube-system और gatekeeper-system को बाहर करता है। सिस्टम पॉड में Localhost प्रोफ़ाइल इंजेक्ट करना जो DaemonSet स्थापना से पहले हो सकते हैं, टूटे हुए प्रोफ़ाइल संदर्भ का जोखिम पैदा करता है यदि फ़ाइल अभी तक नोड पर मौजूद नहीं है। Kyverno नीति को इस बहिष्करण की आवश्यकता नहीं है क्योंकि Kyverno वेबहुक ऑर्डरिंग को अधिक सुंदरता से संभालता है, लेकिन आवश्यकता पड़ने पर वहां भी exclude नियम जोड़े जा सकते हैं।
सशर्त इंजेक्शन, ओवरराइड नहीं। Kyverno MutatingPolicy CEL matchCondition और Gatekeeper MustNotExist पथ परीक्षण दोनों का मतलब है कि प्रवेश नीति केवल तभी कार्य करती है जब पॉड में कोई मौजूदा seccompProfile न हो। जो वर्कलोड पहले से अपनी स्वयं की प्रोफ़ाइल घोषित करते हैं — जिनमें वे भी शामिल हैं जिन्हें कस्टम अनुमति-सूची के माध्यम से वैध रूप से AF_ALG की आवश्यकता होती है — अछूते रहते हैं।