Skip to content

Allow compilation & running in a different chroot - #3653

Open
vmcj wants to merge 10 commits into
DOMjudge:mainfrom
vmcj:custom_compile_chroot
Open

Allow compilation & running in a different chroot#3653
vmcj wants to merge 10 commits into
DOMjudge:mainfrom
vmcj:custom_compile_chroot

Conversation

@vmcj

@vmcj vmcj commented Jun 6, 2026

Copy link
Copy Markdown
Member

We discussed this a bit during NWERC, it would be nice to have a different chroot for specific problems or languages, this is the first step towards that goal.

It does uncover an interesting thing with either my setup or a race condition (with this or old code) somewhere. In case you shut down the judgedaemon with ctrl+c even if the judgedaemon is idle it complains that the chroot-start-stop can´t remove all directories.

@vmcj
vmcj force-pushed the custom_compile_chroot branch from 58da773 to 790dc1b Compare June 6, 2026 14:24
@vmcj
vmcj requested a review from meisterT July 3, 2026 18:14

@meisterT meisterT left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is missing a change to the sudoers config as well

while getopts "c:" opt; do
case $opt in
c)
CHROOTDIR="${CHROOTDIR//domjudge/$OPTARG}"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about handling $OPTARG relative to $(dirname "$CHROOTDIR") (or checking if it's an absolute path) rather than doing string substitution on domjudge?

One catch with ${CHROOTDIR//domjudge/$OPTARG} is that if a language has no custom chroot set it replaces domjudge with default and looks for /chroot/default instead of the original /chroot/domjudge. It would also be tricky if someone configured --with-judgehost-chrootdir with a path that doesn't include the literal word domjudge.

Perhaps something like:

if [ -z "$OPTARG" ] || [ "$OPTARG" = "default" ]; then                                                                                                               
        # keep default CHROOTDIR                                                                                                                                         
        :                                                                                                                                                                
elif [[ "$OPTARG" = /* ]]; then                                                                                                                                      
        CHROOTDIR="$OPTARG"                                                                                                                                              
else                                                                                                                                                                 
        CHROOTDIR="$(dirname "$CHROOTDIR")/$OPTARG"                                                                                                                      
fi                                                                                                                                                                   

What are your thoughts?

set -e
}

CHROOTDIR_OPT=""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like CHROOTDIR_OPT might be unused?

@@ -119,9 +136,9 @@ case "$1" in
rmdir dev || true

for i in $SUBDIRMOUNTS ; do

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In stop, checking $CHROOTDIR/$i to decide whether to unmount or remove symlinks could be slightly fragile if stop is called without -c or with a different chroot than the one currently mounted.

Could we check the target in $PWD directly instead? That way stop wouldn't need to know which chroot was originally mounted to clean up properly.

if ($chroot_run !== $this->chroot_current) {
logmsg(LOG_INFO, " 🔏 Submission should be done in different chroot '" . $chroot_run . "', leaving chroot '" . $this->chroot_current . "'");
logmsg(LOG_INFO, " 🔓 Executing chroot script: '" . self::CHROOT_SCRIPT . " stop'");
sleep(1);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all the sleep(1)s intentional or debugging? We optimized them out years ago and this regresses the state.

return Verdict::INTERNAL_ERROR;
}

$chroot_run = $run_config['chroot'] ?? 'default';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we missing something like this here?

$this->chroot_current = $chroot_run;

}

$chroot_compare = $run_config['chroot'] ?? 'default';
if ($chroot_compare !== $this->chroot_current) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point in execution, the working directory has already been changed to $realWorkdir if I am not mistaken so running chroot-startstop.sh here would try to mount inside the pass subdirectory rather than the judging workdir.

}

$chroot_compile = $compile_config['chroot'] ?? 'default';
if ($chroot_compile !== $this->chroot_current) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should extract all of this duplication into some helper logic.

#[Serializer\Exclude]
private Collection $problems;

#[ORM\Column(length: 32, nullable: true, options: ['comment' => 'Custom chroot for executable'])]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, we should probably add Serializer\Exclude.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps also #[Assert\Regex] constraint (e.g. ^[a-zA-Z0-9_-]+$) to ensure only clean directory names?

private Collection $problems;

#[ORM\Column(length: 32, nullable: true, options: ['comment' => 'Custom chroot for executable'])]
private ?string $chroot_directory;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: chrootDirectory

'required' => false,
]);
$builder->add('chrootDirectory', TextType::class, [
'required' => false,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a descriptive help message here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants