Reliable way of detecting snap confinement mode

I’m currently working a snap that is runnable both under strict and classic confinement, however, some runtime environment changes must be made to make the application work properly in different confinement(strict, classic, and even jail), is there a reliable way to do so?

Currently what I know of:

In classic confinement snap’s HOME environment variable isn’t same as the user’s real home directory

real_home_dir="$(
    getent \
        passwd \
        "${USER}" \
    | cut \
        --delimiter=: \
        --fields=6
)"

# Don't do anything in classic confinement
if test "${HOME}" != "${real_home_dir}"; then

But it didn’t work in --jailmode, where the snap still using the user’s real home directory.

Parsing snap.yaml

From https://github.com/ubuntu/snapcraft-desktop-helpers/blob/de8dc06/common/init#L47-L48:

# Don't LD_PRELOAD bindtextdomain for classic snaps
if ! grep -qs "^\s*confinement:\s*classic\s*" $SNAP/meta/snap.yaml; then
  if [ -f $SNAP/lib/bindtextdomain.so ]; then
    export LD_PRELOAD=$LD_PRELOAD:$SNAP/lib/bindtextdomain.so
  fi
fi

IMO there should be a snapctl get-confinement command or a SNAP_CONFINEMENT_MODE environment variable to simplify the detection.

1 Like

I implemented a bash function for the detection:

# Output: strict, classic, or jail
detect_snapd_confinenment_mode(){
    local \
        real_home_dir
    
    real_home_dir="$(
        getent \
            passwd \
            "${USER}" \
        | cut \
            --delimiter=: \
            --fields=6
    )"
    
    # strict or classic?
    if test "${HOME}" != "${real_home_dir}"; then
        printf strict
    else # classic or jail?
        local file_under_test
    
        if test -e ~/.bashrc; then
            file_under_test=~/.bashrc
        elif test -e ~/.profile; then
            file_under_test=~/.profile
        elif test -e ~/.config; then
            file_under_test=~/.config
        else
            file_under_test=none
        fi

        # In jail mode, HOME is set to the user's real home, but interface restrictions (i.e. no dotfiles access right under HOME) applies.
        if test "${file_under_test}" != none; then
            if cat "${file_under_test}" &> /dev/null; then
                printf classic
            else
                printf jail
            fi
        else
            # assume classic
            printf classic
        fi
    fi
}

@Lin-Buo-Ren - I’m sure you’re aware, but this method is a little noisy since it will generate a security policy violation every time the function is run.

It might be nice to expose this via snapenv. Eg, SNAP_CONFINEMENT=strict.

2 Likes

Yes, that would be straight-forward and helpful.

or just do:

$ snap run --shell gimp
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

$ grep confinement $SNAP/meta/snap.yaml|sed 's/^.*: //'
strict

(it is a required field and $SNAP/meta/snap.yaml always exists)

3 Likes