Search code examples
yoctobitbake

Correct handling of persistent files for readonly rootfs


I want my rootfs to be readonly. As far as I found out there a few measures that need to be done to achieve that before setting the "readonly-rootfs" in EXTRA_IMAGE_FEATURES. Right now, I'm trying to move the files passwd, shadow, gshadow and group from /etc in the rootfs to a persistent storage, namely /data/etc and how the following recipe which basically does the job:

ROOTFS_POSTPROCESS_COMMAND += "move_to_persistent;"

WANT_PERSISTENT = " \ 
    shadow \
    gshadow  \
    passwd  \
    group  \
"

PERSISTENT_TARGET_DIRECTORY = "${D}"

# Testing a different location here in rootfs with the same result
# as described in the stack overflow question
# PERSISTENT_TARGET_DIRECTORY = "${IMAGE_ROOTFS}/test"

FROM = "${IMAGE_ROOTFS}${sysconfdir}"
TO = "${PERSISTENT_TARGET_DIRECTORY}/data${sysconfdir}"

move_to_persistent () {
    install -d ${TO}

    for fn in ${WANT_PERSISTENT}; do
        mv ${FROM}/$fn ${TO}/$fn
        ln -r -s ${TO}/$fn ${FROM}/$fn
    done
}

Unfortunately, I get the following error that useradd command did not succeed.. And in fact when I check the ownership of the moved files I see my host user as owner there:

[...]/my-image/1.0-r0/image/data/etc/
total 16
-rw-r--r-- 1 marius marius  639 Mai 19 12:47 group
-rw------- 1 marius marius  536 Mai 19 12:47 gshadow
-rw-r--r-- 1 marius marius 1025 Mai 19 12:47 passwd
-rw------- 1 marius marius  649 Mai 19 12:47 shadow

Now, the question is: How do I set or preserve the correct ownership of the files and do you see other problems ahead with this approach? Thank you all in advance!


Solution

  • Simply symlinking /etc/passwd to writable storage does not work because of the checks made by passwd and other tools. There are a couple of things that would work, which I will mention below. But before that, using passwd implies that you are using passwords for authentication, which is not the most secure way of doing it. Maybe you could use a certificate of some sort (as with ssh keys) or some kind of web authentication

    Anyhow, here are two ways to get passwd to work...

    1. Use a bind mount

    Copy /etc to a directory in a writable partition, named /data in the example. Note that you have to copy the whole of /etc because passwd needs to create several files in there during the update

    Do this once (at build time)

    cp -a /etc /data
    

    Do this at boot time

    mount --bind /data/etc /etc
    
    1. Use overlayfs

    Build your kernel with CONFIG_OVERLAY_FS. Then you can do something like this:

    Do this once (at build time)

    mkdir -p /data/etc/work /data/etc/upper
    

    Do this at boot time

    mount -t overlay \
          -o lowerdir=/etc,upperdir=/data/etc/upper,workdir=/data/etc/work \
           overlay /etc
    

    Any changes to /etc are actually recorded in /data/etc/upper, but will appear to be in /etc.

    I am not giving OpenEmbedded recipes to implement either of these solutions here because the changes are pretty trivial but dependent on the exact configuration you are building