विल अन्सिबल एक शेल स्क्रिप्ट में 'आरएम -आरएफ /' के निष्पादन को रोक देगा


23

यह यहाँ इस धोखा सवाल पर आधारित है । वर्णित समस्या एक बैश स्क्रिप्ट है जिसमें प्रभाव के लिए कुछ शामिल है:

rm -rf {pattern1}/{pattern2}

... जो कि यदि दोनों प्रतिमानों में एक या एक से अधिक खाली तत्व शामिल हैं, तो कम से कम एक उदाहरण में विस्तार होगा rm -rf /, यह मानते हुए कि मूल आदेश को सही ढंग से स्थानांतरित किया गया था और ओपी पैरामीटर विस्तार के बजाय ब्रेस विस्तार कर रहा था ।

ओपी के गुण्डों के स्पष्टीकरण में , उन्होंने कहा:

आदेश [...] हानिरहित है, लेकिन ऐसा लगता है कि लगभग किसी ने ध्यान नहीं दिया है।

Ansible उपकरण इन त्रुटियों को रोकता है, [...] लेकिन [...] किसी को भी यह पता नहीं लगता था, अन्यथा वे जानते होंगे कि मैंने जो वर्णन किया है वह हो ही नहीं सकता।

तो यह मानते हुए कि आपके पास एक शेल स्क्रिप्ट है जो rm -rf /ब्रेस विस्तार या पैरामीटर विस्तार के माध्यम से एक कमांड का उत्सर्जन करता है , क्या यह सच है कि Ansible का उपयोग करने से उस कमांड को निष्पादित होने से रोका जा सकेगा , और यदि हां, तो यह कैसे करता है?

क्या rm -rf /रूट विशेषाधिकारों के साथ निष्पादन वास्तव में "हानिरहित" है जब तक आप इसे करने के लिए Ansible का उपयोग कर रहे हैं?


4
मैंने बहस की कि इस सवाल का क्या करना है, लेकिन आखिरकार मैंने इसे खत्म करने और इसका जवाब देने का फैसला किया, ताकि अंत में इस पूरे खेदजनक हास्यास्पद गड़बड़ को डाल दिया जाए जहां यह है।
माइकल हैम्पटन

मुझे लगता है कि उत्तर वास्तव में rmस्रोत में निहित है , जिसका मैंने नीचे विश्लेषण किया था।
आरोन हॉल

जवाबों:


54

मेरे पास आभासी मशीनें हैं, चलो उनमें से एक गुच्छा उड़ा दें! विज्ञान के लिए।

[root@diaf ~]# ansible --version
ansible 2.0.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides

पहला प्रयास:

[root@diaf ~]# cat killme.yml 
---
- hosts: localhost
  gather_facts: False
  tasks:
    - name: Die in a fire
      command: "rm -rf {x}/{y}"
[root@diaf ~]# ansible-playbook -l localhost -vvv killme.yml
Using /etc/ansible/ansible.cfg as config file
1 plays in killme.yml

PLAY ***************************************************************************

TASK [Die in a fire] ***********************************************************
task path: /root/killme.yml:5
ESTABLISH LOCAL CONNECTION FOR USER: root
localhost EXEC /bin/sh -c '( umask 22 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1461128819.56-86533871334374 `" && echo "` echo $HOME/.ansible/tmp/ansible-tmp-1461128819.56-86533871334374 `" )'
localhost PUT /tmp/tmprogfhZ TO /root/.ansible/tmp/ansible-tmp-1461128819.56-86533871334374/command
localhost EXEC /bin/sh -c 'LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/python /root/.ansible/tmp/ansible-tmp-1461128819.56-86533871334374/command; rm -rf "/root/.ansible/tmp/ansible-tmp-1461128819.56-86533871334374/" > /dev/null 2>&1'
changed: [localhost] => {"changed": true, "cmd": ["rm", "-rf", "{x}/{y}"], "delta": "0:00:00.001844", "end": "2016-04-20 05:06:59.601868", "invocation": {"module_args": {"_raw_params": "rm -rf {x}/{y}", "_uses_shell": false, "chdir": null, "creates": null, "executable": null, "removes": null, "warn": true}, "module_name": "command"}, "rc": 0, "start": "2016-04-20 05:06:59.600024", "stderr": "", "stdout": "", "stdout_lines": [], "warnings": ["Consider using file module with state=absent rather than running rm"]}
 [WARNING]: Consider using file module with state=absent rather than running rm


PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0

ठीक है, तो commandबस शाब्दिक के साथ गुजरता है, और कुछ भी नहीं होता है।

कैसे हमारे पसंदीदा सुरक्षा बाईपास के बारे में raw?

[root@diaf ~]# cat killme.yml
---
- hosts: localhost
  gather_facts: False
  tasks:
    - name: Die in a fire
      raw: "rm -rf {x}/{y}"
[root@diaf ~]# ansible-playbook -l localhost -vvv killme.yml
Using /etc/ansible/ansible.cfg as config file
1 plays in killme.yml

PLAY ***************************************************************************

TASK [Die in a fire] ***********************************************************
task path: /root/killme.yml:5
ESTABLISH LOCAL CONNECTION FOR USER: root
localhost EXEC rm -rf {x}/{y}
ok: [localhost] => {"changed": false, "invocation": {"module_args": {"_raw_params": "rm -rf {x}/{y}"}, "module_name": "raw"}, "rc": 0, "stderr": "", "stdout": "", "stdout_lines": []}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0

फिर नहीं जाना! संभवतः आपकी सभी फ़ाइलों को हटाना कितना कठिन हो सकता है?

ओह, लेकिन क्या होगा अगर वे अपरिभाषित चर या कुछ और थे?

[root@diaf ~]# cat killme.yml
---
- hosts: localhost
  gather_facts: False
  tasks:
    - name: Die in a fire
      command: "rm -rf {{x}}/{{y}}"
[root@diaf ~]# ansible-playbook -l localhost -vvv killme.yml
Using /etc/ansible/ansible.cfg as config file
1 plays in killme.yml

PLAY ***************************************************************************

TASK [Die in a fire] ***********************************************************
task path: /root/killme.yml:5
fatal: [localhost]: FAILED! => {"failed": true, "msg": "'x' is undefined"}

NO MORE HOSTS LEFT *************************************************************
        to retry, use: --limit @killme.retry

PLAY RECAP *********************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1

खैर, यह काम नहीं किया।

लेकिन क्या होगा अगर चर परिभाषित किए जाते हैं, लेकिन खाली?

[root@diaf ~]# cat killme.yml 
---
- hosts: localhost
  gather_facts: False
  tasks:
    - name: Die in a fire
      command: "rm -rf {{x}}/{{y}}"
  vars:
    x: ""
    y: ""
[root@diaf ~]# ansible-playbook -l localhost -vvv killme.yml
Using /etc/ansible/ansible.cfg as config file
1 plays in killme.yml

PLAY ***************************************************************************

TASK [Die in a fire] ***********************************************************
task path: /root/killme.yml:5
ESTABLISH LOCAL CONNECTION FOR USER: root
localhost EXEC /bin/sh -c '( umask 22 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1461129132.63-211170666238105 `" && echo "` echo $HOME/.ansible/tmp/ansible-tmp-1461129132.63-211170666238105 `" )'
localhost PUT /tmp/tmp78m3WM TO /root/.ansible/tmp/ansible-tmp-1461129132.63-211170666238105/command
localhost EXEC /bin/sh -c 'LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/python /root/.ansible/tmp/ansible-tmp-1461129132.63-211170666238105/command; rm -rf "/root/.ansible/tmp/ansible-tmp-1461129132.63-211170666238105/" > /dev/null 2>&1'
fatal: [localhost]: FAILED! => {"changed": true, "cmd": ["rm", "-rf", "/"], "delta": "0:00:00.001740", "end": "2016-04-20 05:12:12.668616", "failed": true, "invocation": {"module_args": {"_raw_params": "rm -rf /", "_uses_shell": false, "chdir": null, "creates": null, "executable": null, "removes": null, "warn": true}, "module_name": "command"}, "rc": 1, "start": "2016-04-20 05:12:12.666876", "stderr": "rm: it is dangerous to operate recursively on ‘/’\nrm: use --no-preserve-root to override this failsafe", "stdout": "", "stdout_lines": [], "warnings": ["Consider using file module with state=absent rather than running rm"]}

NO MORE HOSTS LEFT *************************************************************
        to retry, use: --limit @killme.retry

PLAY RECAP *********************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1

अंत में, कुछ प्रगति! लेकिन यह अभी भी शिकायत करता है कि मैंने उपयोग नहीं किया --no-preserve-root

बेशक, यह भी मुझे चेतावनी देता है कि मुझे मॉड्यूल का उपयोग करने कीfile कोशिश करनी चाहिए और state=absent। चलो देखते हैं कि अगर काम करता है।

[root@diaf ~]# cat killme.yml 
---
- hosts: localhost
  gather_facts: False
  tasks:
    - name: Die in a fire
      file: path="{{x}}/{{y}}" state=absent
  vars:
    x: ""
    y: ""
[root@diaf ~]# ansible-playbook -l localhost -vvv killme.yml    
Using /etc/ansible/ansible.cfg as config file
1 plays in killme.yml

PLAY ***************************************************************************

TASK [Die in a fire] ***********************************************************
task path: /root/killme.yml:5
ESTABLISH LOCAL CONNECTION FOR USER: root
localhost EXEC /bin/sh -c '( umask 22 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1461129394.62-191828952911388 `" && echo "` echo $HOME/.ansible/tmp/ansible-tmp-1461129394.62-191828952911388 `" )'
localhost PUT /tmp/tmpUqLzyd TO /root/.ansible/tmp/ansible-tmp-1461129394.62-191828952911388/file
localhost EXEC /bin/sh -c 'LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/python /root/.ansible/tmp/ansible-tmp-1461129394.62-191828952911388/file; rm -rf "/root/.ansible/tmp/ansible-tmp-1461129394.62-191828952911388/" > /dev/null 2>&1'
fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_args": {"backup": null, "content": null, "delimiter": null, "diff_peek": null, "directory_mode": null, "follow": false, "force": false, "group": null, "mode": null, "original_basename": null, "owner": null, "path": "/", "recurse": false, "regexp": null, "remote_src": null, "selevel": null, "serole": null, "setype": null, "seuser": null, "src": null, "state": "absent", "validate": null}, "module_name": "file"}, "msg": "rmtree failed: [Errno 16] Device or resource busy: '/boot'"}

NO MORE HOSTS LEFT *************************************************************
        to retry, use: --limit @killme.retry

PLAY RECAP *********************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1

सबके लिए अच्छी खबर है! यह मेरी सभी फाइलों को हटाने की कोशिश करने लगा ! लेकिन दुर्भाग्य से यह एक त्रुटि में बदल गया। मैं उस फिक्सिंग को छोड़ दूंगा और fileपाठक को एक अभ्यास के रूप में मॉड्यूल का उपयोग करके सब कुछ नष्ट करने के लिए प्लेबुक प्राप्त करूंगा ।


इस बिंदु से परे आपके द्वारा देखी जाने वाली कोई भी प्लेबुक न चलाएं! आप देखेंगे कि एक क्षण में क्यों।

अंत में, तख्तापलट के लिए ...

[root@diaf ~]# cat killme.yml
---
- hosts: localhost
  gather_facts: False
  tasks:
    - name: Die in a fire
      raw: "rm -rf {{x}}/{{y}}"
  vars:
    x: ""
    y: "*"
[root@diaf ~]# ansible-playbook -l localhost -vvv killme.yml
Using /etc/ansible/ansible.cfg as config file
1 plays in killme.yml

PLAY ***************************************************************************

TASK [Die in a fire] ***********************************************************
task path: /root/killme.yml:5
ESTABLISH LOCAL CONNECTION FOR USER: root
localhost EXEC rm -rf /*
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/ansible/executor/process/result.py", line 102, in run
  File "/usr/lib/python2.7/site-packages/ansible/executor/process/result.py", line 76, in _read_worker_result
  File "/usr/lib64/python2.7/multiprocessing/queues.py", line 117, in get
ImportError: No module named task_result

यह VM एक पूर्व-तोता है !

दिलचस्प है, ऊपर के commandबजाय के साथ कुछ भी करने में विफल रहा raw। यह बस के fileसाथ उपयोग करने के बारे में एक ही चेतावनी मुद्रित state=absent

मैं यह कहने जा रहा हूं कि ऐसा प्रतीत होता है कि यदि आप इसका उपयोग नहीं कर रहे हैं, तो अमोक rawसे कुछ सुरक्षा है rmआपको इस पर भरोसा नहीं करना चाहिए, हालांकि। मैंने Ansible के कोड के माध्यम से एक त्वरित रूप से देखा, और जब मुझे चेतावनी मिली, तो मुझे ऐसा कुछ भी नहीं मिला जो वास्तव में rmकमांड चलाने के लिए दबा हो ।


10
विज्ञान के लिए +1। मैं होस्ट नाम के लिए +1 अधिक करूंगा, लेकिन यह धोखाधड़ी होगी; पी /
जर्म्समैन गीक

ऐसा लगता है कि आपके पास एक फाइल सिस्टम हो सकता है /boot
84104

1
@ 84104 मजेदार, वह। संयोग से, bootपहली निर्देशिका प्रविष्टि है /। इसलिए कोई फाइल गुम नहीं हुई।
माइकल हैम्पटन

5
@ यर्थाथ! लेकिन, विज्ञान के लिए, कोशिश करें कि rm -rf {{x}}/{{y}}कब yसेट किया जाए "*"--no-preserve-rootजांच यह क्या है के लिए उपयोगी है, लेकिन यह हर संभव स्थिति की आप बाहर निकलना नहीं होगा; यह बाईपास करने के लिए काफी आसान है। यही कारण है कि उस सवाल को तुरंत एक धोखा के रूप में नहीं पकड़ा गया था: खराब अंग्रेजी और स्पष्ट वाक्यविन्यास त्रुटियों को ध्यान में रखते हुए, यह प्रशंसनीय है
माइकल हैम्पटन

1
इसके अलावा raw, cronएक सिस्टम को खराब करने का एक और तरीका खराब हो सकता है।
84104

3

क्या एंसिबल rm -rf /शेल स्क्रिप्ट के निष्पादन को रोक देगा ?

मैंने कोरुटिल्स आरएम स्रोत का निरीक्षण किया , जिसमें निम्नलिखित हैं:

  if (x.recursive && preserve_root)
    {
      static struct dev_ino dev_ino_buf;
      x.root_dev_ino = get_root_dev_ino (&dev_ino_buf);
      if (x.root_dev_ino == NULL)
        error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
               quoteaf ("/"));
    }

रूट से पोंछने का एकमात्र तरीका इस कोड ब्लॉक को प्राप्त करना है। से इस स्रोत :

struct dev_ino *
get_root_dev_ino (struct dev_ino *root_d_i)
{
  struct stat statbuf;
  if (lstat ("/", &statbuf))
    return NULL;
  root_d_i->st_ino = statbuf.st_ino;
  root_d_i->st_dev = statbuf.st_dev;
  return root_d_i;
}

मैं इसका अर्थ यह समझाता हूं कि फ़ंक्शन get_root_dev_inoशून्य हो जाता है /, और इस प्रकार rm विफल हो जाता है।

पहले कोड ब्लॉक (पुनरावृत्ति के साथ) को बायपास करने का एकमात्र तरीका है --no-preserve-rootऔर यह ओवरराइड करने के लिए पर्यावरण चर का उपयोग नहीं करता है, इसलिए इसे आरएम को स्पष्ट रूप से पारित करना होगा।

मेरा मानना है कि यह साबित करता है कि जब तक Ansible स्पष्ट रूप से गुजरता है --no-preserve-rootकरने के लिए rm, यह इस से काम नहीं चलेगा।

निष्कर्ष

मुझे विश्वास नहीं है कि Ansible स्पष्ट रूप से रोकता है rm -rf /क्योंकि rmस्वयं इसे रोकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.