diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc1daf5fe..fa0a9e352 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Parse custom apparmor profile with ABI 3.0 - run: sudo apparmor_parser -r -W apparmor-profiles/home.sandbox.codejail_sandbox-python3.bin.python-abi3 + run: sudo apparmor_parser -r -W apparmor-profiles/home.sandbox.codejail_sandbox.bin.python-abi3 - name: Build latest code changes into CI image run: | @@ -35,7 +35,7 @@ jobs: - name: Run container with custom apparmor profile and codejail CI image run: | - docker run --name=codejail --privileged -d --security-opt apparmor=apparmor_profile \ + docker run --name=codejail --privileged -d --security-opt apparmor=openedx_codejail_sandbox \ openedx-codejail tail -f /dev/null - name: Run Tests diff --git a/Dockerfile b/Dockerfile index c55ac2c82..3e625cdf7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,7 @@ +# Used for running codejail unit tests. +# +# Sandbox path and ABI version must be kept in sync with AppArmor profile. + ARG ubuntu_version="24.04" FROM ubuntu:${ubuntu_version} @@ -19,7 +23,7 @@ RUN pip install virtualenv ENV CODEJAIL_GROUP=sandbox ENV CODEJAIL_SANDBOX_CALLER=ubuntu ENV CODEJAIL_TEST_USER=sandbox -ENV CODEJAIL_TEST_VENV=/home/sandbox/codejail_sandbox-python${python_version} +ENV CODEJAIL_TEST_VENV=/home/sandbox/codejail_sandbox # Create Virtualenv for sandbox user RUN virtualenv -p python${python_version} --always-copy $CODEJAIL_TEST_VENV @@ -65,7 +69,7 @@ RUN pip install -r /codejail/requirements/sandbox.txt -r /codejail/requirements/ COPY . /codejail # Setup sudoers file -COPY sudoers-file/01-sandbox-python-${python_version} /etc/sudoers.d/01-sandbox +COPY sudoers-file/01-sandbox-python /etc/sudoers.d/01-sandbox # Change Sudoers file permissions RUN chmod 0440 /etc/sudoers.d/01-sandbox diff --git a/README.rst b/README.rst index 8bf174f63..470507749 100644 --- a/README.rst +++ b/README.rst @@ -112,61 +112,17 @@ Other details here that depend on your configuration: (Note that the ``find`` binary can run arbitrary code, so this is not a safe sudoers file for non-codejail purposes.) 5. Edit an AppArmor profile. This is a text file specifying the limits on the - sandboxed Python executable. The file must be in ``/etc/apparmor.d`` and must + sandboxed Python executable. The file must be in ``/etc/apparmor.d`` and should be named based on the executable, with slashes replaced by dots. For example, if your sandboxed Python is at ``/home/chris/ve/myproj-sandbox/bin/python``, - then your AppArmor profile must be ``/etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python``:: + then your AppArmor profile must be ``/etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python``. - $ sudo vim /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python - - #include - - /bin/python { - #include - #include - - /** mr, - /** mr, - # If you have code that the sandbox must be able to access, add lines - # pointing to those directories: - /the/path/to/your/sandbox-packages/** r, - - /tmp/codejail-*/ rix, - /tmp/codejail-*/** wrix, - } - - Depending on your OS and AppArmor version you may need to specify a policy - ABI to ensure the restrictions are being correctly applied. Modern ubuntu - versions using AppArmor V3 should use the 3.0 ABI in order to enable - network confinment rules. A profile using the ABI 3.0 would look as - follows:: - - $ sudo vim /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python - - abi , - #include - - /bin/python { - #include - #include - - /** mr, - /** mr, - # If you have code that the sandbox must be able to access, add lines - # pointing to those directories: - /the/path/to/your/sandbox-packages/** r, - - /tmp/codejail-*/ rix, - /tmp/codejail-*/** wrix, - } - - You can also look at the - ``apparmor-profiles/home.sandbox.codejail_sandbox-python3.bin.python-abi3`` - file which is used for testing for a full profile example. + See sample profile in ``apparmor-profiles/``. The profile **must be + customized** to match your sandbox location. 6. Parse the profiles:: - $ sudo apparmor_parser + $ sudo apparmor_parser --replace --warn=all --warn=no-debug-cache --Werror 7. Reactivate your project's main virtualenv again. diff --git a/apparmor-profiles/home.sandbox.codejail_sandbox-python3.bin.python-abi3 b/apparmor-profiles/home.sandbox.codejail_sandbox-python3.bin.python-abi3 deleted file mode 100644 index 3183954a5..000000000 --- a/apparmor-profiles/home.sandbox.codejail_sandbox-python3.bin.python-abi3 +++ /dev/null @@ -1,64 +0,0 @@ -abi , -#include -profile apparmor_profile /home/sandbox/codejail_sandbox-python{3.[0-9],3.[1-9][0-9]}/bin/python { - #include - #include - - # Deny network access and socket operations - # Note: If this profile is being run on a docker container - # then this directive might not be sufficient. Docker network - # interfaces are created in a different namespace from the one that - # apparmor can monitor and manage and so apparmor can't always deny - # network access to the container. Please be sure to test - # network access from within your container for the jailed process - # to be sure that everything is secure. - deny network, - - /usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/**.{pyc,so,so.*[0-9]} mr, - /usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/**.{egg,py,pth} r, - /usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/ r, - /usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/**/ r, - /usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/*.dist-info/{METADATA,namespace_packages.txt} r, - /usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/*.VERSION r, - /usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/*.egg-info/PKG-INFO r, - /usr/{local/,}lib{,32,64}/python3.{1,}[0-9]/lib-dynload/*.so mr, - - # Site-wide configuration - /etc/python{2.[4-7],3.[0-9],3.[1-9][0-9]}/** r, - - # shared python paths - /usr/share/{pyshared,pycentral,python-support}/** r, - /{var,usr}/lib/{pyshared,pycentral,python-support}/** r, - /usr/lib/{pyshared,pycentral,python-support}/**.so mr, - /var/lib/{pyshared,pycentral,python-support}/**.pyc mr, - /usr/lib/python3/dist-packages/**.so mr, - - # wx paths - /usr/lib/wx/python/*.pth r, - - # python build configuration and headers - /usr/include/python{2.[4-7],3.[0-9],3.[1-9][0-9]}*/pyconfig.h r, - - # Include additions to the abstraction - include if exists - - /home/sandbox/codejail_sandbox-python{3.[0-9],3.[1-9][0-9]}/** mr, - /tmp/codejail-*/ rix, - /tmp/codejail-*/** wrix, - - # Whitelist particiclar shared objects from the system - # python installation - # - /usr/lib/python{3.[0-9],3.[1-9][0-9]}/lib-dynload/_json.so mr, - /usr/lib/python{3.[0-9],3.[1-9][0-9]}/lib-dynload/_ctypes.so mr, - /usr/lib/python{3.[0-9],3.[1-9][0-9]}/lib-dynload/_heapq.so mr, - /usr/lib/python{3.[0-9],3.[1-9][0-9]}/lib-dynload/_io.so mr, - /usr/lib/python{3.[0-9],3.[1-9][0-9]}/lib-dynload/_csv.so mr, - /usr/lib/python{3.[0-9],3.[1-9][0-9]}/lib-dynload/datetime.so mr, - /usr/lib/python{3.[0-9],3.[1-9][0-9]}/lib-dynload/_elementtree.so mr, - /usr/lib/python{3.[0-9],3.[1-9][0-9]}/lib-dynload/pyexpat.so mr, - # - # Allow access to selections from /proc - # - /proc/*/mounts r, -} diff --git a/apparmor-profiles/home.sandbox.codejail_sandbox.bin.python-abi3 b/apparmor-profiles/home.sandbox.codejail_sandbox.bin.python-abi3 new file mode 100644 index 000000000..dc9732d50 --- /dev/null +++ b/apparmor-profiles/home.sandbox.codejail_sandbox.bin.python-abi3 @@ -0,0 +1,77 @@ +# Used for running codejail unit tests, but should also be maintained as a +# general example. +# +# Sandbox path must be kept in sync with Dockerfile. + + +# AppArmor profile for running codejail. +# +# Changes to this profile must be coordinated carefully with changes to the +# filesystem layout -- in particular, the sandbox path must match, otherwise +# the profile will provide no security at all. +# +# #=========# +# # WARNING # +# #=========# +# +# Failure to apply a secure apparmor profile *will* likely result in a +# full compromise of the host by an attacker. AppArmor is *mandatory* +# for using codejail -- this is not just for hardening. +# +# This profile is written for AppArmor 3 or higher (Ubuntu 22.04 or higher). + + + +# Require that the system understands the feature set that this policy was written +# for. If we didn't include this, then on Ubuntu >= 22.04, AppArmor might assume +# the wrong feature set was requested, and some rules might become too permissive. +# See https://github.com/netblue30/firejail/issues/3659#issuecomment-711074899 +# +# This should also be set to match the installed AppArmor version. +abi , + +# Sets standard variables used by abstractions/base, later. Controlled +# by OS, see /etc/apparmor.d/tunables/global for contents. +include + +# `mediate_deleted` instructs apparmor to continue to make policy decisions +# in cases where a confined executable has a file descriptor even after the +# file is removed from the filesystem. It's unclear if this is important for +# sandboxing, but it doesn't seem like it would loosen security or interfere +# with functionality to include it. +# +# `no_attach_disconnected` is default, but is explicitly indicated +# here because `attach_disconnected` is very commonly used in +# example profiles despite being a security risk (due to allowing +# disconnected objects to masquerade as other, trusted paths in the +# filesystem). +profile openedx_codejail_sandbox /home/sandbox/codejail_sandbox/bin/python flags=(mediate_deleted, no_attach_disconnected) { + + # Allow access to a variety of commonly needed, generally safe things + # (such as reading /usr/lib, /dev/random, free memory levels, etc.) + # + # Manpage: "Includes files that should be readable and writable in all profiles." + # + # We could instead list these directives explicitly out of caution but + # it would get pretty verbose. + include + + # Read and run binaries and libraries in the virtualenv. This + # includes the sandbox's copy of Python as well as any + # dependencies that have been installed for inclusion in + # sandboxes. + # + # m: executable mapping, required for shared libraries used by some + # Python dependencies with C compontents, eg `nltk`. + /home/sandbox/codejail_sandbox/** mr, + + # Allow access to the temporary directories that are set up by + # codejail, one for each code-exec call. Each /tmp/code-XXXXX + # contains one execution. + /tmp/codejail-*/ rix, + /tmp/codejail-*/** wrix, + + # Allow receiving a kill signal from the webapp when the execution + # runs beyond time limits. + signal (receive) set=(kill), +} diff --git a/sudoers-file/01-sandbox-python-3.11 b/sudoers-file/01-sandbox-python similarity index 65% rename from sudoers-file/01-sandbox-python-3.11 rename to sudoers-file/01-sandbox-python index 46c3cb2a7..a59bc508d 100644 --- a/sudoers-file/01-sandbox-python-3.11 +++ b/sudoers-file/01-sandbox-python @@ -1,7 +1,9 @@ -ubuntu ALL=(sandbox) SETENV:NOPASSWD:/home/sandbox/codejail_sandbox-python3.11/bin/python +# Used for running codejail unit tests. + +ubuntu ALL=(sandbox) SETENV:NOPASSWD:/home/sandbox/codejail_sandbox/bin/python ubuntu ALL=(sandbox) SETENV:NOPASSWD:/usr/bin/find ubuntu ALL=(ALL) NOPASSWD:/usr/bin/pkill -Defaults!/home/sandbox/codejail_sandbox-python3.11/bin/python !requiretty +Defaults!/home/sandbox/codejail_sandbox/bin/python !requiretty Defaults!/usr/bin/find !requiretty Defaults!/usr/bin/pkill !requiretty diff --git a/sudoers-file/01-sandbox-python-3.8 b/sudoers-file/01-sandbox-python-3.8 deleted file mode 100644 index bd7f51a93..000000000 --- a/sudoers-file/01-sandbox-python-3.8 +++ /dev/null @@ -1,7 +0,0 @@ -ubuntu ALL=(sandbox) SETENV:NOPASSWD:/home/sandbox/codejail_sandbox-python3.8/bin/python -ubuntu ALL=(sandbox) SETENV:NOPASSWD:/usr/bin/find -ubuntu ALL=(ALL) NOPASSWD:/usr/bin/pkill - -Defaults!/home/sandbox/codejail_sandbox-python3.8/bin/python !requiretty -Defaults!/usr/bin/find !requiretty -Defaults!/usr/bin/pkill !requiretty