Executing a bash script or a c binary on a file system with noexec option












1














Can anyone explain in details what is going on with the following. Let's imagine I am mounting a directory with noexec option as follows:



mount -o noexec /dev/mapper/fedora-data /data


So to verify this I ran mount | grep data:



/dev/mapper/fedora-data on /data type ext4 (rw,noexec,relatime,seclabel,data=ordered)


Now within /data I'm creating a simple script called hello_world as follows:



#!/bin/bash

echo "Hello World"
whoami


So I made the script executable by chmod o+x hello_world (this will however have no effect on a file system with noexec options) and I tried running it:



# ./hello_world
-bash: ./hello_world: Permission denied


However, prepanding bash to the file yields to:



# bash hello_world
Hello World
root


So then I created a simple hello_world.c with the following contents:



#include <stdio.h>

int main()
{
printf("Hello Worldn");
return 0;
}


Compiled it using cc -o hello_world.c hello_world



Now running:



# ./hello_world
-bash: ./hello_world: Permission denied


So I tried to run it using



/lib64/ld-linux-x86-64.so.2 hello_world


The error:



./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted


So this is of course true since ldd returns the following:



ldd hello_world
ldd: warning: you do not have execution permission for `./hello_world'
not a dynamic executable


On another system where noexec mount option doesn't apply I see:



ldd hellow_world
linux-vdso.so.1 (0x00007ffc1c127000)
libc.so.6 => /lib64/libc.so.6 (0x00007facd9d5a000)
/lib64/ld-linux-x86-64.so.2 (0x00007facd9f3e000)


Now my question is this: Why does running a bash script on a file system with noexec option work but not a c code? What is happening under the hood?










share|improve this question



























    1














    Can anyone explain in details what is going on with the following. Let's imagine I am mounting a directory with noexec option as follows:



    mount -o noexec /dev/mapper/fedora-data /data


    So to verify this I ran mount | grep data:



    /dev/mapper/fedora-data on /data type ext4 (rw,noexec,relatime,seclabel,data=ordered)


    Now within /data I'm creating a simple script called hello_world as follows:



    #!/bin/bash

    echo "Hello World"
    whoami


    So I made the script executable by chmod o+x hello_world (this will however have no effect on a file system with noexec options) and I tried running it:



    # ./hello_world
    -bash: ./hello_world: Permission denied


    However, prepanding bash to the file yields to:



    # bash hello_world
    Hello World
    root


    So then I created a simple hello_world.c with the following contents:



    #include <stdio.h>

    int main()
    {
    printf("Hello Worldn");
    return 0;
    }


    Compiled it using cc -o hello_world.c hello_world



    Now running:



    # ./hello_world
    -bash: ./hello_world: Permission denied


    So I tried to run it using



    /lib64/ld-linux-x86-64.so.2 hello_world


    The error:



    ./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted


    So this is of course true since ldd returns the following:



    ldd hello_world
    ldd: warning: you do not have execution permission for `./hello_world'
    not a dynamic executable


    On another system where noexec mount option doesn't apply I see:



    ldd hellow_world
    linux-vdso.so.1 (0x00007ffc1c127000)
    libc.so.6 => /lib64/libc.so.6 (0x00007facd9d5a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007facd9f3e000)


    Now my question is this: Why does running a bash script on a file system with noexec option work but not a c code? What is happening under the hood?










    share|improve this question

























      1












      1








      1







      Can anyone explain in details what is going on with the following. Let's imagine I am mounting a directory with noexec option as follows:



      mount -o noexec /dev/mapper/fedora-data /data


      So to verify this I ran mount | grep data:



      /dev/mapper/fedora-data on /data type ext4 (rw,noexec,relatime,seclabel,data=ordered)


      Now within /data I'm creating a simple script called hello_world as follows:



      #!/bin/bash

      echo "Hello World"
      whoami


      So I made the script executable by chmod o+x hello_world (this will however have no effect on a file system with noexec options) and I tried running it:



      # ./hello_world
      -bash: ./hello_world: Permission denied


      However, prepanding bash to the file yields to:



      # bash hello_world
      Hello World
      root


      So then I created a simple hello_world.c with the following contents:



      #include <stdio.h>

      int main()
      {
      printf("Hello Worldn");
      return 0;
      }


      Compiled it using cc -o hello_world.c hello_world



      Now running:



      # ./hello_world
      -bash: ./hello_world: Permission denied


      So I tried to run it using



      /lib64/ld-linux-x86-64.so.2 hello_world


      The error:



      ./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted


      So this is of course true since ldd returns the following:



      ldd hello_world
      ldd: warning: you do not have execution permission for `./hello_world'
      not a dynamic executable


      On another system where noexec mount option doesn't apply I see:



      ldd hellow_world
      linux-vdso.so.1 (0x00007ffc1c127000)
      libc.so.6 => /lib64/libc.so.6 (0x00007facd9d5a000)
      /lib64/ld-linux-x86-64.so.2 (0x00007facd9f3e000)


      Now my question is this: Why does running a bash script on a file system with noexec option work but not a c code? What is happening under the hood?










      share|improve this question













      Can anyone explain in details what is going on with the following. Let's imagine I am mounting a directory with noexec option as follows:



      mount -o noexec /dev/mapper/fedora-data /data


      So to verify this I ran mount | grep data:



      /dev/mapper/fedora-data on /data type ext4 (rw,noexec,relatime,seclabel,data=ordered)


      Now within /data I'm creating a simple script called hello_world as follows:



      #!/bin/bash

      echo "Hello World"
      whoami


      So I made the script executable by chmod o+x hello_world (this will however have no effect on a file system with noexec options) and I tried running it:



      # ./hello_world
      -bash: ./hello_world: Permission denied


      However, prepanding bash to the file yields to:



      # bash hello_world
      Hello World
      root


      So then I created a simple hello_world.c with the following contents:



      #include <stdio.h>

      int main()
      {
      printf("Hello Worldn");
      return 0;
      }


      Compiled it using cc -o hello_world.c hello_world



      Now running:



      # ./hello_world
      -bash: ./hello_world: Permission denied


      So I tried to run it using



      /lib64/ld-linux-x86-64.so.2 hello_world


      The error:



      ./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted


      So this is of course true since ldd returns the following:



      ldd hello_world
      ldd: warning: you do not have execution permission for `./hello_world'
      not a dynamic executable


      On another system where noexec mount option doesn't apply I see:



      ldd hellow_world
      linux-vdso.so.1 (0x00007ffc1c127000)
      libc.so.6 => /lib64/libc.so.6 (0x00007facd9d5a000)
      /lib64/ld-linux-x86-64.so.2 (0x00007facd9f3e000)


      Now my question is this: Why does running a bash script on a file system with noexec option work but not a c code? What is happening under the hood?







      linux bash fedora filesystems c






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked 5 hours ago









      Valentin Bajrami

      5,82911627




      5,82911627






















          3 Answers
          3






          active

          oldest

          votes


















          2














          Executing command on this way:



          bash hello_world


          you make bash read from file hello_world (which is not forbidden).



          In other cases OS try to run this file hello_world and fail because of noexec flag






          share|improve this answer





















          • Well the kernel will check the shebang to decide what instructions to expect/run. So running ./hello_world would mean the same right or am I missing the point here?
            – Valentin Bajrami
            4 hours ago










          • @ValentinBajrami, no, they execute on different way. Think about no execution flag on the file.
            – Romeo Ninov
            4 hours ago





















          2














          What's happening in both cases is the same: to execute a file directly, the execute bit needs to be set, and the filesystem can't be mounted noexec. But these things don't stop reading those files.



          The noexec filesystem option just plain isn't as smart as you'd like it to be. In the case of the bash script run as ./hello_world, the #! line isn't even checked, because the system sees that it should ignore the executable bit before even trying to run the file.



          In the case of bash ./hello_world, the script is never "executed" in the relevant sense. Instead, /bin/bash is, and that then loads the file and does stuff. In the case of bash or another shell, the "stuff" is "execute a bunch of commands", but _now we're "past" anything that's going to check file execute bits. That check isn't responsible for what happens later.



          Consider this case:



          $ cat hello_world | /bin/bash


          … or for those who do not like Pointless Use of Cat:



          $ /bin/bash < hello_world


          The "shbang" #! sequence at the beginning of a file is just some nice magic for doing exactly the same thing — when you try to execute the file as a command. You might find this LWN.net article helpful: How programs get run.






          share|improve this answer































            0














            Because the bash executable doesn't reside on said filesystem.






            share|improve this answer

















            • 1




              That is true but running ./hello_world would also us /bin/bash which doesn't reside on a file system with noexec option mounted. If that is true then the c program would run as well corerct?
              – Valentin Bajrami
              4 hours ago






            • 1




              Nope. That's not the way it works.
              – tink
              4 hours ago











            Your Answer








            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "106"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f490402%2fexecuting-a-bash-script-or-a-c-binary-on-a-file-system-with-noexec-option%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            3 Answers
            3






            active

            oldest

            votes








            3 Answers
            3






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            2














            Executing command on this way:



            bash hello_world


            you make bash read from file hello_world (which is not forbidden).



            In other cases OS try to run this file hello_world and fail because of noexec flag






            share|improve this answer





















            • Well the kernel will check the shebang to decide what instructions to expect/run. So running ./hello_world would mean the same right or am I missing the point here?
              – Valentin Bajrami
              4 hours ago










            • @ValentinBajrami, no, they execute on different way. Think about no execution flag on the file.
              – Romeo Ninov
              4 hours ago


















            2














            Executing command on this way:



            bash hello_world


            you make bash read from file hello_world (which is not forbidden).



            In other cases OS try to run this file hello_world and fail because of noexec flag






            share|improve this answer





















            • Well the kernel will check the shebang to decide what instructions to expect/run. So running ./hello_world would mean the same right or am I missing the point here?
              – Valentin Bajrami
              4 hours ago










            • @ValentinBajrami, no, they execute on different way. Think about no execution flag on the file.
              – Romeo Ninov
              4 hours ago
















            2












            2








            2






            Executing command on this way:



            bash hello_world


            you make bash read from file hello_world (which is not forbidden).



            In other cases OS try to run this file hello_world and fail because of noexec flag






            share|improve this answer












            Executing command on this way:



            bash hello_world


            you make bash read from file hello_world (which is not forbidden).



            In other cases OS try to run this file hello_world and fail because of noexec flag







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 4 hours ago









            Romeo Ninov

            5,13231827




            5,13231827












            • Well the kernel will check the shebang to decide what instructions to expect/run. So running ./hello_world would mean the same right or am I missing the point here?
              – Valentin Bajrami
              4 hours ago










            • @ValentinBajrami, no, they execute on different way. Think about no execution flag on the file.
              – Romeo Ninov
              4 hours ago




















            • Well the kernel will check the shebang to decide what instructions to expect/run. So running ./hello_world would mean the same right or am I missing the point here?
              – Valentin Bajrami
              4 hours ago










            • @ValentinBajrami, no, they execute on different way. Think about no execution flag on the file.
              – Romeo Ninov
              4 hours ago


















            Well the kernel will check the shebang to decide what instructions to expect/run. So running ./hello_world would mean the same right or am I missing the point here?
            – Valentin Bajrami
            4 hours ago




            Well the kernel will check the shebang to decide what instructions to expect/run. So running ./hello_world would mean the same right or am I missing the point here?
            – Valentin Bajrami
            4 hours ago












            @ValentinBajrami, no, they execute on different way. Think about no execution flag on the file.
            – Romeo Ninov
            4 hours ago






            @ValentinBajrami, no, they execute on different way. Think about no execution flag on the file.
            – Romeo Ninov
            4 hours ago















            2














            What's happening in both cases is the same: to execute a file directly, the execute bit needs to be set, and the filesystem can't be mounted noexec. But these things don't stop reading those files.



            The noexec filesystem option just plain isn't as smart as you'd like it to be. In the case of the bash script run as ./hello_world, the #! line isn't even checked, because the system sees that it should ignore the executable bit before even trying to run the file.



            In the case of bash ./hello_world, the script is never "executed" in the relevant sense. Instead, /bin/bash is, and that then loads the file and does stuff. In the case of bash or another shell, the "stuff" is "execute a bunch of commands", but _now we're "past" anything that's going to check file execute bits. That check isn't responsible for what happens later.



            Consider this case:



            $ cat hello_world | /bin/bash


            … or for those who do not like Pointless Use of Cat:



            $ /bin/bash < hello_world


            The "shbang" #! sequence at the beginning of a file is just some nice magic for doing exactly the same thing — when you try to execute the file as a command. You might find this LWN.net article helpful: How programs get run.






            share|improve this answer




























              2














              What's happening in both cases is the same: to execute a file directly, the execute bit needs to be set, and the filesystem can't be mounted noexec. But these things don't stop reading those files.



              The noexec filesystem option just plain isn't as smart as you'd like it to be. In the case of the bash script run as ./hello_world, the #! line isn't even checked, because the system sees that it should ignore the executable bit before even trying to run the file.



              In the case of bash ./hello_world, the script is never "executed" in the relevant sense. Instead, /bin/bash is, and that then loads the file and does stuff. In the case of bash or another shell, the "stuff" is "execute a bunch of commands", but _now we're "past" anything that's going to check file execute bits. That check isn't responsible for what happens later.



              Consider this case:



              $ cat hello_world | /bin/bash


              … or for those who do not like Pointless Use of Cat:



              $ /bin/bash < hello_world


              The "shbang" #! sequence at the beginning of a file is just some nice magic for doing exactly the same thing — when you try to execute the file as a command. You might find this LWN.net article helpful: How programs get run.






              share|improve this answer


























                2












                2








                2






                What's happening in both cases is the same: to execute a file directly, the execute bit needs to be set, and the filesystem can't be mounted noexec. But these things don't stop reading those files.



                The noexec filesystem option just plain isn't as smart as you'd like it to be. In the case of the bash script run as ./hello_world, the #! line isn't even checked, because the system sees that it should ignore the executable bit before even trying to run the file.



                In the case of bash ./hello_world, the script is never "executed" in the relevant sense. Instead, /bin/bash is, and that then loads the file and does stuff. In the case of bash or another shell, the "stuff" is "execute a bunch of commands", but _now we're "past" anything that's going to check file execute bits. That check isn't responsible for what happens later.



                Consider this case:



                $ cat hello_world | /bin/bash


                … or for those who do not like Pointless Use of Cat:



                $ /bin/bash < hello_world


                The "shbang" #! sequence at the beginning of a file is just some nice magic for doing exactly the same thing — when you try to execute the file as a command. You might find this LWN.net article helpful: How programs get run.






                share|improve this answer














                What's happening in both cases is the same: to execute a file directly, the execute bit needs to be set, and the filesystem can't be mounted noexec. But these things don't stop reading those files.



                The noexec filesystem option just plain isn't as smart as you'd like it to be. In the case of the bash script run as ./hello_world, the #! line isn't even checked, because the system sees that it should ignore the executable bit before even trying to run the file.



                In the case of bash ./hello_world, the script is never "executed" in the relevant sense. Instead, /bin/bash is, and that then loads the file and does stuff. In the case of bash or another shell, the "stuff" is "execute a bunch of commands", but _now we're "past" anything that's going to check file execute bits. That check isn't responsible for what happens later.



                Consider this case:



                $ cat hello_world | /bin/bash


                … or for those who do not like Pointless Use of Cat:



                $ /bin/bash < hello_world


                The "shbang" #! sequence at the beginning of a file is just some nice magic for doing exactly the same thing — when you try to execute the file as a command. You might find this LWN.net article helpful: How programs get run.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited 2 hours ago

























                answered 4 hours ago









                mattdm

                27.9k1172111




                27.9k1172111























                    0














                    Because the bash executable doesn't reside on said filesystem.






                    share|improve this answer

















                    • 1




                      That is true but running ./hello_world would also us /bin/bash which doesn't reside on a file system with noexec option mounted. If that is true then the c program would run as well corerct?
                      – Valentin Bajrami
                      4 hours ago






                    • 1




                      Nope. That's not the way it works.
                      – tink
                      4 hours ago
















                    0














                    Because the bash executable doesn't reside on said filesystem.






                    share|improve this answer

















                    • 1




                      That is true but running ./hello_world would also us /bin/bash which doesn't reside on a file system with noexec option mounted. If that is true then the c program would run as well corerct?
                      – Valentin Bajrami
                      4 hours ago






                    • 1




                      Nope. That's not the way it works.
                      – tink
                      4 hours ago














                    0












                    0








                    0






                    Because the bash executable doesn't reside on said filesystem.






                    share|improve this answer












                    Because the bash executable doesn't reside on said filesystem.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered 4 hours ago









                    tink

                    4,12811218




                    4,12811218








                    • 1




                      That is true but running ./hello_world would also us /bin/bash which doesn't reside on a file system with noexec option mounted. If that is true then the c program would run as well corerct?
                      – Valentin Bajrami
                      4 hours ago






                    • 1




                      Nope. That's not the way it works.
                      – tink
                      4 hours ago














                    • 1




                      That is true but running ./hello_world would also us /bin/bash which doesn't reside on a file system with noexec option mounted. If that is true then the c program would run as well corerct?
                      – Valentin Bajrami
                      4 hours ago






                    • 1




                      Nope. That's not the way it works.
                      – tink
                      4 hours ago








                    1




                    1




                    That is true but running ./hello_world would also us /bin/bash which doesn't reside on a file system with noexec option mounted. If that is true then the c program would run as well corerct?
                    – Valentin Bajrami
                    4 hours ago




                    That is true but running ./hello_world would also us /bin/bash which doesn't reside on a file system with noexec option mounted. If that is true then the c program would run as well corerct?
                    – Valentin Bajrami
                    4 hours ago




                    1




                    1




                    Nope. That's not the way it works.
                    – tink
                    4 hours ago




                    Nope. That's not the way it works.
                    – tink
                    4 hours ago


















                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Unix & Linux Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f490402%2fexecuting-a-bash-script-or-a-c-binary-on-a-file-system-with-noexec-option%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Accessing regular linux commands in Huawei's Dopra Linux

                    Can't connect RFCOMM socket: Host is down

                    Kernel panic - not syncing: Fatal Exception in Interrupt