diff --git a/test-images/demo-python3/Dockerfile b/test-images/demo-python3/Dockerfile index 89033a2cfe0c3cfe64cde534bbbf1cfbc81597b2..471854b2cf1772a7e4075625fbeb34296a66cac1 100644 --- a/test-images/demo-python3/Dockerfile +++ b/test-images/demo-python3/Dockerfile @@ -1,5 +1,11 @@ FROM python:3.13.0b3-alpine3.20 + +# Create a less-privileged user to run student's code and install sudo +RUN addgroup -S student && adduser -S student -G student +RUN apk add --no-cache --update sudo + WORKDIR /usr/src/app COPY ./grade.sh grade.sh RUN chmod +x grade.sh + CMD ["./grade.sh"] diff --git a/test-images/demo-python3/README.md b/test-images/demo-python3/README.md index d85e6996aa5d685b41753e7e6c7fd4c1568d556a..5f81582726073041b0dc013817a1c234a049c613 100644 --- a/test-images/demo-python3/README.md +++ b/test-images/demo-python3/README.md @@ -19,8 +19,9 @@ After building the image you can try out the grading image locally, by mounting Example submissions are provided in `./test_submissions`. For instance, to grade the correct submission `/test_submissions/correct.py` using the image, run the following command: ```bash +rm -rf feedback mkdir feedback -docker run -v ./feedback:/data/feedback -v ./test_submissions/correct.py:/data/submission/script.py demo-python3 +docker run --rm -v ./feedback:/data/feedback -v ./test_submissions/correct.py:/data/submission/script.py demo-python3 cat feedback/grade.json ``` diff --git a/test-images/demo-python3/grade.sh b/test-images/demo-python3/grade.sh index c9e792a7995cf046123d2c297cccc783fa13c68c..aec09ff0c527e6449d5a55ebcdbf821e1d422bbd 100644 --- a/test-images/demo-python3/grade.sh +++ b/test-images/demo-python3/grade.sh @@ -3,32 +3,42 @@ save_feedback() { grade=$1 feedback=$2 + # Feedback must be saved in `/data/feedback`. # - `grade.json`, must be a JSON file with {"grade": grade_as_a_number} # - other file are attached as feedback files + echo "[*] Saving grade $grade and feedback \"$feedback\"" mkdir -p /data/feedback echo "{\"grade\": $grade}" > /data/feedback/grade.json echo "$feedback" > /data/feedback/feedback.txt + exit 0 } grade() { # Files submitted by the student are mounted in `/data/submission`. - if [ -f /data/submission/script.py ]; then - output=$(python3 /data/submission/script.py) - echo "[*] Python output: $output" - if [ "Hello World!" == "$output" ]; then - save_feedback 100 "The output is correct, well done! :)" - else - save_feedback 0 "The output is not correct :'(" - fi - else + + if [ ! -f /data/submission/script.py ]; then save_feedback 0 "I have not found the script.py file :'(" fi + + # Run the script under the restricted `student` user with a timeout of 1 + # minute, and capture the output. + cp /data/submission/script.py /home/student/script.py + chmod -R 700 /data + chmod 755 /home/student/script.py + output=$(timeout 1m sudo -u student python3 /home/student/script.py 2>&1) + + echo "[*] Python output: $output" + if [ "$output" == "Hello World!" ]; then + save_feedback 100 "The output is correct, well done! :)" + else + save_feedback 0 "The output is not correct :'(" + fi } handle_internal_error() { - save_feedback 0 "An internal error occurred, please contact your teacher." + save_feedback 0 "An internal error occurred, please contact the teaching team." } -# Important: always exit with 0 +# Important: make sure to always exit with 0 grade || handle_internal_error diff --git a/test-images/demo-python3/test_submissions/malicious.py b/test-images/demo-python3/test_submissions/malicious.py new file mode 100755 index 0000000000000000000000000000000000000000..3951052e7f548bcc87a23c075b9567103714ea88 --- /dev/null +++ b/test-images/demo-python3/test_submissions/malicious.py @@ -0,0 +1,13 @@ +import os +import json + +os.system("ls -l /data/submission") +os.system("whoami") + +os.makedirs('/data/feedback', exist_ok=True) + +with open("/data/feedback/grade.json", "w") as f: + json.dump({"grade": 100}, f) + +with open("/data/feedback/ahah.txt", "w") as f: + f.write("Ahah")