@@ -27,12 +27,91 @@ void raw_image_handler(void);
void raw_file_handler(void);
void raw_copyimage_handler(void);
+/**
+ * Handle write protection for block devices
+ *
+ * Automatically remove write protection for block devices if:
+ * - The device name starts with /dev/*
+ * - The device is a block device
+ * - A corresponding ro flag e.g. /sys/class/block/mmcblk0boot0/force_ro is available
+ * - The force_ro flag can be opened writeable
+ */
+static int blkprotect(struct img_type *img, bool on)
+{
+ const char c_sys_path[] = "/sys/class/block/%s/force_ro";
+ const char c_unprot_char = '0';
+ const char c_prot_char = '1';
+ int ret = 0; // 0 means OK nothing to do, 1 OK unprotected, 2 OK protected, negative means error
+ int ret_int = 0;
+ char *sysfs_path = NULL;
+ int fd_force_ro;
+ struct stat sb;
+ char current_prot;
+
+ if (strncmp("/dev/", img->device, 5) != 0) {
+ return ret;
+ }
+
+ if (stat(img->device, &sb) == -1) {
+ TRACE("stat for device %s failed: %s", img->device, strerror(errno));
+ return ret;
+ }
+ if(!S_ISBLK(sb.st_mode)) {
+ return ret;
+ }
+
+ ret_int = asprintf(&sysfs_path, c_sys_path, img->device + 5); // remove "/dev/" from device path
+ if(ret_int < 0) {
+ ret = -ENOMEM;
+ goto blkprotect_out;
+ }
+
+ if (access(sysfs_path, W_OK) == -1) {
+ goto blkprotect_out;
+ }
+
+ // There is a ro flag, the device needs to be protected or unprotected
+ fd_force_ro = open(sysfs_path, O_RDWR);
+ if (fd_force_ro == -1) {
+ ret = -EBADF;
+ goto blkprotect_out;
+ }
+
+ ssize_t n = read(fd_force_ro, ¤t_prot, 1);
+ if (n != 1) {
+ ret = -EBADFD;
+ }
+ if (on == false) {
+ if (current_prot == c_prot_char) {
+ write(fd_force_ro, &c_unprot_char, 1);
+ TRACE("Device %s: read-only protection disabled", img->device);
+ ret = 1;
+ }
+ } else {
+ if (current_prot == c_unprot_char) {
+ write(fd_force_ro, &c_prot_char, 1);
+ TRACE("Device %s: read-only protection enabled", img->device);
+ ret = 2;
+ }
+ }
+ close(fd_force_ro);
+
+blkprotect_out:
+ if(sysfs_path)
+ free(sysfs_path);
+ return ret;
+}
+
static int install_raw_image(struct img_type *img,
void __attribute__ ((__unused__)) *data)
{
int ret;
int fdout;
+ int prot_stat = blkprotect(img, false);
+ if (prot_stat < 0)
+ return prot_stat;
+
fdout = open(img->device, O_RDWR);
if (fdout < 0) {
TRACE("Device %s cannot be opened: %s",
@@ -45,6 +124,11 @@ static int install_raw_image(struct img_type *img,
ret = copyimage(&fdout, img, NULL);
#endif
+ if (prot_stat == 1) {
+ fsync(fdout); // At least with Linux 4.14 data are not automatically flushed before ro mode is enabled
+ blkprotect(img, true); // no error handling, keep ret from copyimage
+ }
+
close(fdout);
return ret;
}
Some block devices support physical write protection. The kernel provides a standard interface to enable or disable protection in /sys/class/block/*/force_ro. This patch adds functionality to automatically detect these memory types. If read-only mode is enabled on the partition on which the image must be written, swupdate temporarily switches to read/write mode. Signed-off-by: Adrian Freihofer <adrian.freihofer@siemens.com> --- handlers/raw_handler.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)