Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e18c0d50 authored by Nick Kralevich's avatar Nick Kralevich
Browse files

fs_mgr: make block devices read-only

When a filesystem is mounted read-only, make the underlying
block device read-only too. This helps prevent an attacker
who is able to change permissions on the files in /dev
(for example, symlink attack) from modifying the block device.

In particular, this change would have stopped the LG Thrill / Optimus
3D rooting exploit
(http://vulnfactory.org/blog/2012/02/26/rooting-the-lg-thrill-optimus-3d/)
as that exploit modified the raw block device corresponding to /system.

This change also makes UID=0 less powerful. Block devices cannot
be made writable again without CAP_SYS_ADMIN, so an escalation
to UID=0 by itself doesn't give full root access.

adb/mount: Prior to mounting something read-write, remove the
read-only restrictions on the underlying block device. This avoids
messing up developer workflows.

Change-Id: I135098a8fe06f327336f045aab0d48ed9de33807
parent 072ee014
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -72,6 +72,8 @@ static char *find_mount(const char *dir)
static int remount_system()
{
    char *dev;
    int fd;
    int OFF = 0;

    if (system_ro == 0) {
        return 0;
@@ -82,6 +84,13 @@ static int remount_system()
    if (!dev)
        return -1;

    fd = unix_open(dev, O_RDONLY);
    if (fd < 0)
        return -1;

    ioctl(fd, BLKROSET, &OFF);
    adb_close(fd);

    system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);

    free(dev);
+42 −5
Original line number Diff line number Diff line
@@ -487,6 +487,43 @@ static void remove_trailing_slashes(char *n)
    }
}

/*
 * Mark the given block device as read-only, using the BLKROSET ioctl.
 * Return 0 on success, and -1 on error.
 */
static void fs_set_blk_ro(const char *blockdev)
{
    int fd;
    int ON = 1;

    fd = open(blockdev, O_RDONLY);
    if (fd < 0) {
        // should never happen
        return;
    }

    ioctl(fd, BLKROSET, &ON);
    close(fd);
}

/*
 * __mount(): wrapper around the mount() system call which also
 * sets the underlying block device to read-only if the mount is read-only.
 * See "man 2 mount" for return values.
 */
static int __mount(const char *source, const char *target,
                   const char *filesystemtype, unsigned long mountflags,
                   const void *data)
{
    int ret = mount(source, target, filesystemtype, mountflags, data);

    if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
        fs_set_blk_ro(source);
    }

    return ret;
}

static int fs_match(char *in1, char *in2)
{
    char *n1;
@@ -539,7 +576,7 @@ int fs_mgr_mount_all(struct fstab *fstab)
                     fstab->recs[i].mount_point);
        }

        mret = mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
        mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
                       fstab->recs[i].fs_type, fstab->recs[i].flags,
                       fstab->recs[i].fs_options);
        if (!mret) {
@@ -621,7 +658,7 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
        } else {
            m = fstab->recs[i].mount_point;
        }
        if (mount(n_blk_device, m, fstab->recs[i].fs_type,
        if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
                    fstab->recs[i].flags, fstab->recs[i].fs_options)) {
            ERROR("Cannot mount filesystem on %s at %s\n",
                    n_blk_device, m);
+22 −0
Original line number Diff line number Diff line
@@ -137,6 +137,24 @@ parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra, i
	return rwflag;
}

/*
 * Mark the given block device as read-write, using the BLKROSET ioctl.
 */
static void fs_set_blk_rw(const char *blockdev)
{
    int fd;
    int OFF = 0;

    fd = open(blockdev, O_RDONLY);
    if (fd < 0) {
        // should never happen
        return;
    }

    ioctl(fd, BLKROSET, &OFF);
    close(fd);
}

static char *progname;

static struct extra_opts extra;
@@ -178,6 +196,10 @@ do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data, int
        dev = loopdev;
    }

    if ((rwflag & MS_RDONLY) == 0) {
        fs_set_blk_rw(dev);
    }

	while ((s = strsep(&type, ",")) != NULL) {
retry:
		if (mount(dev, dir, s, rwflag, data) == -1) {