Add option to disable the concurrent write protection

This allows writing to the filesystem from the host computer and
CircuitPython by increasing the risk of filesystem corruption.
This commit is contained in:
Scott Shawcroft 2019-02-19 14:45:45 -08:00
parent b1e8c43679
commit 1a0596a2fb
No known key found for this signature in database
GPG Key ID: FD0EDC4B6C53CA59
12 changed files with 69 additions and 41 deletions

View File

@ -38,6 +38,8 @@
#define FSUSER_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it
// Device is writable over USB and read-only to MicroPython.
#define FSUSER_USB_WRITABLE (0x0010)
// Bit set when the above flag is checked before opening a file for write.
#define FSUSER_CONCURRENT_WRITE_PROTECTED (0x0020)
typedef struct _fs_user_mount_t {
mp_obj_base_t base;

View File

@ -34,6 +34,7 @@
#include "py/mperrno.h"
#include "lib/oofatfs/ff.h"
#include "extmod/vfs_fat.h"
#include "supervisor/filesystem.h"
// this table converts from FRESULT to POSIX errno
const byte fresult_to_errno_table[20] = {
@ -187,7 +188,7 @@ STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_ar
}
}
assert(vfs != NULL);
if ((vfs->flags & FSUSER_USB_WRITABLE) != 0 && (mode & FA_WRITE) != 0) {
if ((mode & FA_WRITE) != 0 && !filesystem_is_writable_by_python(vfs)) {
mp_raise_OSError(MP_EROFS);
}

@ -1 +1 @@
Subproject commit 29b49199beb8e9b5fead83e5cd36105f8746f1d7
Subproject commit 55874813f82157b7509729b1a0c66e68f86e2d07

7
main.c
View File

@ -323,12 +323,12 @@ void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
mp_hal_delay_ms(1500);
// USB isn't up, so we can write the file.
filesystem_writable_by_python(true);
filesystem_set_internal_writable_by_usb(false);
f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
// Switch the filesystem back to non-writable by Python now instead of later,
// since boot.py might change it back to writable.
filesystem_writable_by_python(false);
filesystem_set_internal_writable_by_usb(true);
// Write version info to boot_out.txt.
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
@ -416,7 +416,8 @@ int __attribute__((used)) main(void) {
// By default our internal flash is readonly to local python code and
// writable over USB. Set it here so that boot.py can change it.
filesystem_writable_by_python(false);
filesystem_set_internal_concurrent_write_protection(true);
filesystem_set_internal_writable_by_usb(true);
run_boot_py(safe_mode);

View File

@ -48,16 +48,18 @@
//| directly.
//|
//| .. function:: mount(filesystem, mount_path, \*, readonly=False)
//| .. function:: mount(filesystem, mount_path, \*, readonly=False, disable_concurrent_write_protection=False)
//|
//| Mounts the given filesystem object at the given path.
//|
//| This is the CircuitPython analog to the UNIX ``mount`` command.
//|
//| :param bool readonly: True when the filesystem should be readonly to CircuitPython.
//|
mp_obj_t storage_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_readonly };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} },
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
};
// parse args
@ -77,7 +79,7 @@ mp_obj_t storage_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg
mp_raise_ValueError(translate("filesystem must provide mount method"));
}
common_hal_storage_mount(vfs_obj, mnt_str, mp_obj_is_true(args[ARG_readonly].u_obj));
common_hal_storage_mount(vfs_obj, mnt_str, args[ARG_readonly].u_bool);
return mp_const_none;
}
@ -101,14 +103,21 @@ mp_obj_t storage_umount(mp_obj_t mnt_in) {
}
MP_DEFINE_CONST_FUN_OBJ_1(storage_umount_obj, storage_umount);
//| .. function:: remount(mount_path, readonly=False)
//| .. function:: remount(mount_path, readonly=False, *, disable_concurrent_write_protection=False)
//|
//| Remounts the given path with new parameters.
//|
//| :param bool readonly: True when the filesystem should be readonly to CircuitPython.
//| :param bool disable_concurrent_write_protection: When True, the check that makes sure the
//| underlying filesystem data is written by one computer is disabled. Disabling the protection
//| allows CircuitPython and a host to write to the same filesystem with the risk that the
//| filesystem will be corrupted.
//|
mp_obj_t storage_remount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_readonly };
enum { ARG_readonly, ARG_disable_concurrent_write_protection };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_readonly, MP_ARG_BOOL | MP_ARG_REQUIRED, {.u_bool = false} },
{ MP_QSTR_readonly, MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_disable_concurrent_write_protection, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
};
// get the mount point
@ -118,7 +127,7 @@ mp_obj_t storage_remount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
common_hal_storage_remount(mnt_str, args[ARG_readonly].u_bool);
common_hal_storage_remount(mnt_str, args[ARG_readonly].u_bool, args[ARG_disable_concurrent_write_protection].u_bool);
return mp_const_none;
}

View File

@ -33,7 +33,7 @@
void common_hal_storage_mount(mp_obj_t vfs_obj, const char* path, bool readonly);
void common_hal_storage_umount_path(const char* path);
void common_hal_storage_umount_object(mp_obj_t vfs_obj);
void common_hal_storage_remount(const char* path, bool readonly);
void common_hal_storage_remount(const char* path, bool readonly, bool disable_concurrent_write_protection);
mp_obj_t common_hal_storage_getmount(const char* path);
void common_hal_storage_erase_filesystem(void);

View File

@ -143,7 +143,7 @@ mp_obj_t common_hal_storage_getmount(const char *mount_path) {
return storage_object_from_path(mount_path);
}
void common_hal_storage_remount(const char *mount_path, bool readonly) {
void common_hal_storage_remount(const char *mount_path, bool readonly, bool disable_concurrent_write_protection) {
if (strcmp(mount_path, "/") != 0) {
mp_raise_OSError(MP_EINVAL);
}
@ -156,7 +156,8 @@ void common_hal_storage_remount(const char *mount_path, bool readonly) {
}
#endif
supervisor_flash_set_usb_writable(readonly);
filesystem_set_internal_writable_by_usb(readonly);
filesystem_set_internal_concurrent_write_protection(!disable_concurrent_write_protection);
}
void common_hal_storage_erase_filesystem(void) {

View File

@ -29,9 +29,16 @@
#include <stdbool.h>
#include "extmod/vfs_fat.h"
void filesystem_init(bool create_allowed, bool force_create);
void filesystem_flush(void);
void filesystem_writable_by_python(bool writable);
bool filesystem_present(void);
void filesystem_set_internal_writable_by_usb(bool usb_writable);
void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection);
void filesystem_set_writable_by_usb(fs_user_mount_t *vfs, bool usb_writable);
void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concurrent_write_protection);
bool filesystem_is_writable_by_python(fs_user_mount_t *vfs);
bool filesystem_is_writable_by_usb(fs_user_mount_t *vfs);
#endif // MICROPY_INCLUDED_SUPERVISOR_FILESYSTEM_H

View File

@ -37,7 +37,6 @@
#include "supervisor/internal_flash.h"
#endif
void supervisor_flash_set_usb_writable(bool usb_writable);
void supervisor_flash_init(void);
uint32_t supervisor_flash_get_block_size(void);
uint32_t supervisor_flash_get_block_count(void);

View File

@ -24,6 +24,8 @@
* THE SOFTWARE.
*/
#include "supervisor/filesystem.h"
#include "extmod/vfs_fat.h"
#include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h"
@ -92,16 +94,42 @@ void filesystem_flush(void) {
supervisor_flash_flush();
}
void filesystem_writable_by_python(bool writable) {
void filesystem_set_internal_writable_by_usb(bool writable) {
fs_user_mount_t *vfs = &_internal_vfs;
if (!writable) {
filesystem_set_writable_by_usb(vfs, writable);
}
void filesystem_set_writable_by_usb(fs_user_mount_t *vfs, bool usb_writable) {
if (usb_writable) {
vfs->flags |= FSUSER_USB_WRITABLE;
} else {
vfs->flags &= ~FSUSER_USB_WRITABLE;
}
}
bool filesystem_is_writable_by_python(fs_user_mount_t *vfs) {
return (vfs->flags & FSUSER_CONCURRENT_WRITE_PROTECTED) == 0 ||
(vfs->flags & FSUSER_USB_WRITABLE) == 0;
}
bool filesystem_is_writable_by_usb(fs_user_mount_t *vfs) {
return (vfs->flags & FSUSER_CONCURRENT_WRITE_PROTECTED) == 0 ||
(vfs->flags & FSUSER_USB_WRITABLE) != 0;
}
void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection) {
filesystem_set_concurrent_write_protection(&_internal_vfs, concurrent_write_protection);
}
void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concurrent_write_protection) {
if (concurrent_write_protection) {
vfs->flags |= FSUSER_CONCURRENT_WRITE_PROTECTED;
} else {
vfs->flags &= ~FSUSER_CONCURRENT_WRITE_PROTECTED;
}
}
bool filesystem_present(void) {
return true;
}

View File

@ -33,26 +33,6 @@
#define PART1_START_BLOCK (0x1)
void supervisor_flash_set_usb_writable(bool usb_writable) {
mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table);
for (uint8_t i = 0; current_mount != NULL; i++) {
if (i == VFS_INDEX) {
break;
}
current_mount = current_mount->next;
}
if (current_mount == NULL) {
return;
}
fs_user_mount_t *vfs = (fs_user_mount_t *) current_mount->obj;
if (usb_writable) {
vfs->flags |= FSUSER_USB_WRITABLE;
} else {
vfs->flags &= ~FSUSER_USB_WRITABLE;
}
}
// there is a singleton Flash object
const mp_obj_type_t supervisor_flash_type;
STATIC const mp_obj_base_t supervisor_flash_obj = {&supervisor_flash_type};

View File

@ -34,6 +34,7 @@
#include "lib/oofatfs/ff.h"
#include "py/mpstate.h"
#include "supervisor/filesystem.h"
#include "supervisor/shared/autoreload.h"
#define MSC_FLASH_BLOCK_SIZE 512
@ -148,8 +149,7 @@ bool tud_msc_is_writable_cb(uint8_t lun) {
if (vfs == NULL) {
return false;
}
if (vfs->writeblocks[0] == MP_OBJ_NULL ||
(vfs->flags & FSUSER_USB_WRITABLE) == 0) {
if (vfs->writeblocks[0] == MP_OBJ_NULL || !filesystem_is_writable_by_usb(vfs)) {
return false;
}
return true;