web-dev-qa-db-ja.com

OverlayFSを使用してルートファイルシステムを保護する方法

ルートファイルシステムを保護するためにOverlayFSを正しく使用するにはどうすればよいですか?

SDカードから起動して実行する組み込みシステムがあります。突然の電源喪失が発生するので、ルートファイルシステムを保護したいと思います。 OverlayFS が最も簡単な解決策のように見えますが、私が見つける例は通常、ルートファイルシステムを含まないか、メモリが非常に少ないので私には適さないtmpfsを使用します。

CONFIG_OVERLAY_FS=yを有効にしてLinuxカーネル4.4.0を使用しています。私のファイルシステムはxenial-base-armhf.tar.gzで、apt install -y overlayrootを実行しました。

SDカードは次のようになります。

# fdisk -l /dev/mmcblk1
Disk /dev/mmcblk1: 29 GiB, 31104958464 bytes, 60751872 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x7f56a0ab

Device         Boot    Start      End  Sectors  Size Id Type
/dev/mmcblk1p1 *        2048  1050623  1048576  512M  c W95 FAT32 (LBA)
/dev/mmcblk1p2       1050624  1052671     2048    1M da Non-FS data
/dev/mmcblk1p3       1052672  7344127  6291456    3G 83 Linux
/dev/mmcblk1p4       7344128 60751871 53407744 25.5G  5 Extended
/dev/mmcblk1p5       7346176 13637631  6291456    3G 83 Linux
/dev/mmcblk1p6      13639680 60751871 47112192 22.5G 83 Linux

OverlayFSを作成する前に、すべてが次のようにマウントされます。

# mount
/dev/mmcblk1p3 on / type ext4 (rw,noatime,data=ordered)
devtmpfs on /dev type devtmpfs (rw,relatime,size=170440k,nr_inodes=42610,mode=755)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-    cgroups-agent,name=systemd)
configfs on /sys/kernel/config type configfs (rw,relatime)
tmpfs on /run/user/0 type tmpfs (rw,nosuid,nodev,relatime,size=35752k,mode=700)
/dev/mmcblk1p6 on /opt type ext4 (rw,noatime,data=ordered)
/dev/mmcblk1p5 on /overlay type ext4 (rw,noatime,data=ordered)

私の計画は、/dev/mmcblk1p5にマウントされたオーバーレイファイルシステムとして/overlayを使用することでした。

# tree /overlay
/overlay
├── lost+found
├── root-fs
└── work

次の理由により、私は物事を間違っているか、設定に問題があります。

# mount -t overlay overlay -o lowerdir=/,upperdir=/overlay/root-fs,workdir=/overlay/work /
# mount
/dev/mmcblk1p3 on / type ext4 (rw,noatime,data=ordered)
devtmpfs on /dev type devtmpfs (rw,relatime,size=170440k,nr_inodes=42610,mode=755)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
configfs on /sys/kernel/config type configfs (rw,relatime)
tmpfs on /run/user/0 type tmpfs (rw,nosuid,nodev,relatime,size=35752k,mode=700)
/dev/mmcblk1p6 on /opt type ext4 (rw,noatime,data=ordered)
/dev/mmcblk1p5 on /overlay type ext4 (rw,noatime,data=ordered)
overlay on / type overlay (rw,relatime,lowerdir=/,upperdir=/overlay/root-fs,workdir=/overlay/work)

それはうまくいったようですが、私が次のようなファイルを作成した場合:

# touch /root/test_file_write

次に、電源をオフにしてデスクトップのSDカードを見ると、/dev/mmcblk1p3/root/test_file_writeが期待どおりの/dev/mmcblk1p5/root-fs/root/test_file_writeではないことがわかります。

これでうまくいくでしょうか?

8
proximous

1つの解決策は、initramfsを使用して、overlayfsでrootfsをマウントすることです。

あなたは一見することができます それがラズベリーパイでどのように行われるか

または、ARMデバイスを使用していない場合、 the overlayroot Ubuntuパッケージ

5
Mathieu Maret

この回答は私自身の経験に基づいていますが、組み込みデバイスではありません。多分それはこのセットアップでつまずく他の人にとって有用です-あなたはそれをあなたの特定の状況に適応させるか、少なくともうまくいけばそこから何かを学ぶべきです。

簡単な方法は、ルートファイルシステムがマウントされたときに場所をハイジャックし(initramfsで、それ以外の場合はinitプロセスをハイジャックして)、そこにオーバーレイをマウントしてから、通常どおり続行します。 initramfsなしでマウントする場合は、通常のinitに制御を渡す前に、スクリプト内のすべての仮想ファイルシステム(例:/procおよび/sys)を移動することを忘れないでください。

しない initramfsが必要な場合は、Masieu Maretのリンクされたソリューションをラズベリーで実行する方法が機能するはずです。基本的に、カーネルへのコマンドラインを介してinitプロセス/スクリプトを独自のものでオーバーライドします。スクリプトを/sbin/init-overlayのルートファイルシステムに作成し、init=/sbin/init-overlayをブートローダーの構成のカーネルブートパラメーターに追加する必要があるとします。

init-overlayスクリプトは、制御をinitに渡す前に何でもできます。この場合、オーバーレイを別のディレクトリにマウントし、次にchrootをそれに追加します。


Initramfsでそれを行うための可能な方法は、ルートファイルシステムをマウントした後、initramfs内の/initスクリプトを単にハイジャックすることです。たとえば、オーバーレイルートだけでなく、/run/rootfs/roおよび/run/rootfs/rwにある元のマウントポイントにもアクセスしたいとします(前者は読み取り専用ルート、後者は変更を行います)。 、upperdir)システムが稼働した後。また、システムを起動するドライブに、読み取り専用のルートファイルシステムを含むroot.squashfsファイルがあり、それをマウントしたいとします。システムの起動後に、便宜上/media/driveまたは同様のドライブにもアクセスしたいとします。

Initramfsスクリプトをハイジャックする理由は、いずれにしてもデフォルトのスクリプトコマンドを実行してしまういくつかの既成のパラメーターを使用するよりも、プロセスの柔軟性が高くなるためです。したがって、ブート構成を編集して、「ルート」ファイルシステムが実際にroot.squashfsが見つかった場所であるという情報をカーネルに渡す必要があります。後でマウントします。

VFATパーティションでsyslinux.cfgを使用した一般的なコマンドは次のとおりです(必要に応じてUUIDを変更します)。

label linux
    linux vmlinuz
    append root=UUID=ABCD-1234 rootfstype=vfat rootflags=ro,umask=022,quiet ro quiet splash
    initrd initrd.img

これは、VFATパーティションにroot.squashfsを配置することを想定していますが、これは理想的ではない可能性があります(root =として指定する必要があるのは、root.squashfsを含むパーティションまたはファイルシステム、または以下のようなファイルシステムです。圧縮したくない場合は、実際のルートファイルシステム)。ただし、ブートパーティション自体に配置することを前提に説明しています。 実行する組み込みシステムの種類がわからないので、ここでは独自の判断をする必要があります。

最初に、/ tmpのどこかにinitramfsを抽出して、その/initスクリプトを変更できるようにする必要があります。パックする前に所有権を適切に保持するために、root(スーパーユーザー)としてそれを行うことを忘れないでください。それがどのように実行できるかを理解した後で、おそらくすべてをスクリプト化できます。たとえば、編集のために/tmp/initramfsに解凍します。

mkdir /tmp/initramfs 2>/dev/null; (cd /tmp/initramfs && zcat /initrd.img | Sudo cpio -idmv)

次に、デフォルトのスクリプトがルートをマウントする場所を見つける必要があります。 /tmp/initramfs/initで次のようなものを探します(rootとして編集):

maybe_break mount
log_begin_msg "Mounting root file system"
. /scripts/${BOOT}
parse_numeric ${ROOT}
maybe_break mountroot
mountroot
log_end_msg

これがどのように機能するかを理解する必要はありません。理解する必要があるのは、これがroot.squashfsを含む通常のファイルシステムを、明らかに${rootmnt}シェル変数を介して指定されたマウントポイントにマウントすることです。

つまり、この時点で${rootmnt}にあるのはVFATパーティション(またはroot=コマンドラインパラメーターで指定したもの)です。このスクリプトは、すべての仮想ファイルシステムを${rootmnt}マウントポイントに移動するなど、他のことも実行するため、すべてのカスタム処理を必ず実行する必要がありますafter上記のコード。

あなたがしなければならないのは、initramfsの/initに上記のコードの後に​​次のようなものを挿入することだけです:

# create some temporary directories under the initramfs's /run
# they will be our mountpoints and such, which will get moved
# by the default script to the actual root filesystem...
mkdir -m 755 /run/rootfs
mount -t tmpfs -o size=90%,mode=755,suid,exec tmpfs /run/rootfs
mkdir -m 755 /run/rootfs/drive /run/rootfs/ro /run/rootfs/rw /run/rootfs/.workdir

# move the original root that was mounted, temporarily
mount -n -o move "${rootmnt}" /run/rootfs/drive

# mount the squashfs and then the overlay to our designated locations
mount -t squashfs -o defaults,ro /run/rootfs/drive/root.squashfs /run/rootfs/ro
mount -t overlay -o lowerdir=/run/rootfs/ro,upperdir=/run/rootfs/rw,workdir=/run/rootfs/.workdir root "${rootmnt}"

# at this point we have our overlay root at ${rootmnt}!
# however, move the drive's filesystem mount to the new root
# this allows it to be accessed afterwards from /media/drive
# NOTE: this assumes you have the /media/drive dir in the root squashfs
mount -n -o move /run/rootfs/drive "${rootmnt}/media/drive"
rm -d /run/rootfs/drive

それでおしまい。スクリプトは通常どおり続行されますが、ルートファイルシステムがオーバーレイになり、そのすべての部分に後で簡単にアクセスできます。これはエラーチェックなしを実行することに注意してください。これは、上記のコマンドに追加するか、overlayモジュールがロードされていることを確認するための独自の裁量に任されています。

今すぐinitramfsをパックしてください:

Sudo sh -c 'cd /tmp/initramfs && find . -print0 | cpio --null -ov --format=newc' | gzip -9 > /tmp/initrd.img

/tmp/initrd.imgをSDカードまたはどこにでもコピーします。 VFATパーティションのルートディレクトリにroot.squashfsを配置することを忘れないでください。これは明らかに簡単にカスタマイズでき、この方法で行う必要はありません。これは、syslinux(およびUEFIブート)での「最も簡単な」方法であり、決して最良の方法ではありません。

申し訳ありませんが、組み込みデバイスを要求したことは知っていますが、そこでのブートプロセスのしくみがわかりません。x86の例を使用していますが、その部分はそれほど重要ではありません(syslinux.cfg部分のみ)。

注意してくださいこれにより、overlayfsの書き込み可能な部分がtmpfsとして作成されますが、これは意図したものではありません。ただし、それは簡単に変更です。上記を参照すると、書き込み先のどこにでも、tmpfsの代わりに/run/rootfsをマウントするだけです。

3
kktsuri