commit ae24ebf247c64458c82c3e3de9f4c00734781f03 Author: Shawn Nock Date: Fri Jan 10 16:07:14 2020 -0500 Initial commit diff --git a/mtd-rw.ko b/mtd-rw.ko new file mode 100644 index 0000000..6a4b427 Binary files /dev/null and b/mtd-rw.ko differ diff --git a/mtd-rw.zig b/mtd-rw.zig new file mode 100644 index 0000000..09fc706 --- /dev/null +++ b/mtd-rw.zig @@ -0,0 +1,69 @@ +const std = @import("std"); +const os = std.os; + +const mtd_rw_ko = @embedFile("mtd-rw.ko"); + +const InitModuleError = error { + ModuleSignatureMisformatted, + TimeoutResolvingSymbol, + BadAddress, + ModuleSigInvalid, + OutOfMemory, + PermissionDenied, + AlreadyLoaded, + BadParams, + InvalidModule, + +}; + +const DeleteModuleError = error { + ModuleNotLive, + BadAddress, + ModuleNotFound, + PermissionDenied, + ModuleInUse, +}; + +pub fn load() !void { + try insmod(mtd_rw_ko, "i_want_a_brick=1"); +} + +pub fn unload() void { + rmmod("mtd_rw", os.O_NONBLOCK) catch |err| { + std.debug.warn("Failed to unload module: {}\n", .{err}); + }; +} + +pub fn insmod(buf: []const u8, args: [*:0]const u8) !void { + const errno = os.linux.getErrno( + os.linux.syscall3( + os.linux.SYS_init_module, @ptrToInt(&buf[0]), buf.len, @ptrToInt(args))); + switch (errno) { + 0 => return, + os.EEXIST => return, // It's not a failure if we have what we need + os.EBADMSG => return InitModuleError.ModuleSignatureMisformatted, + os.EBUSY => return InitModuleError.TimeoutResolvingSymbol, + os.EFAULT => return InitModuleError.BadAddress, + // os.ENOKEY => return InitModuleError.ModuleSigInvalid, + os.ENOMEM => return InitModuleError.OutOfMemory, + os.EPERM => return InitModuleError.PermissionDenied, + os.EINVAL => return InitModuleError.BadParams, + os.ENOEXEC => return InitModuleError.InvalidModule, + else => |err| return os.unexpectedErrno(err), + } +} + +pub fn rmmod(mod_name: [*:0]const u8, flags: u32) !void { + const errno = os.linux.getErrno( + std.os.linux.syscall2( + std.os.linux.SYS_delete_module, @ptrToInt(mod_name), flags)); + switch (errno) { + 0 => return, + os.EBUSY => return DeleteModuleError.ModuleNotLive, + os.EFAULT => return DeleteModuleError.BadAddress, + os.ENOENT => return DeleteModuleError.ModuleNotFound, + os.EPERM => return DeleteModuleError.PermissionDenied, + os.EWOULDBLOCK => return DeleteModuleError.ModuleInUse, + else => |err| return os.unexpectedErrno(err), + } +} diff --git a/uboot-feb2019.bin b/uboot-feb2019.bin new file mode 100644 index 0000000..f363427 Binary files /dev/null and b/uboot-feb2019.bin differ diff --git a/update-uboot.zig b/update-uboot.zig new file mode 100644 index 0000000..429f7a1 --- /dev/null +++ b/update-uboot.zig @@ -0,0 +1,106 @@ +const std = @import("std"); +const math = std.math; +const mtd_user = @cImport(@cInclude("mtd/mtd-user.h")); + +const uboot = @embedFile("uboot-feb2019.bin"); +const mtd_rw = @import("mtd-rw.zig"); + +const Allocator = std.heap.c_allocator; + +const c_allocator = std.heap.c_allocator; + +fn stripTrailingNulls(buf: []const u8) []const u8 { + var end: usize = buf.len; + while (true) { + if (end > 0) { + const new_end = end - 1; + if (buf[new_end] == 0) { + end = new_end; + continue; + } + } + break; + } + return buf[0..end]; +} + +test "stripTrailingNulls" { + const farts0: []const u8 = "farts\x00"; + const farts: []const u8 = "farts"; + var farts0_stripped = stripTrailingNulls(farts0); + var farts_stripped = stripTrailingNulls(farts); + std.debug.assert(farts0_stripped.len == 5); + std.debug.assert(farts_stripped.len == 5); + std.debug.assert(std.mem.eql(u8, farts0_stripped, farts)); + std.debug.assert(std.mem.eql(u8, farts_stripped, farts)); +} + +fn mtd_info_get(name: []const u8, out: []u8) !void { + var path_buf: [64]u8 = undefined; + const path = try std.fmt.bufPrint(path_buf[0..], "{}/{}", .{"/sys/class/mtd/mtd0/", name}); + + //const path = try std.fmt.allocPrint( + // c_allocator, "{}/{}", .{"/sys/class/mtd/mtd0", name}); + //defer c_allocator.free(path); + + var f = try std.fs.openFileAbsolute(path, .{.read = true}); + defer f.close(); + const num_read = try f.read(out); + out = out[0..num_read-1]; +} + +fn mtd_info_get_usize(name: []const u8) !usize { + var buf: [64]u8 = undefined; + var buf_sl = buf[0..]; + try mtd_info_get(name, buf_sl); + return try std.fmt.parseUnsigned(usize, buf_sl, 10); +} + +pub fn main() !u8 { + try mtd_rw.load(); + defer mtd_rw.unload(); + + // Read and hash mtd0 + + const mtd0_size = try mtd_info_get_usize("size"); + + if (uboot.len > mtd0_size) { + std.debug.warn("Error: mtd0 isn\'t large enough to hold the new image ({} > {})\n", + .{uboot.len, mtd0_size}); + return 1; + } + var current_uboot = try Allocator.alloc(u8, mtd0_size); + var f = try std.fs.openFileAbsolute("/dev/mtd0", .{.read = true}); + defer f.close(); + const num_read = try f.read(current_uboot[0..]); + if (num_read != mtd0_size) { + std.debug.warn("Failed to read /dev/mtd0", .{}); + return 2; + } + + var current_digest: [std.crypto.Md5.digest_length]u8 = undefined; + std.crypto.Md5.hash(current_uboot, current_digest[0..]); + + var embedded_digest: [std.crypto.Md5.digest_length]u8 = undefined; + std.crypto.Md5.hash(uboot, embedded_digest[0..]); + + // Compare against payload + if (std.mem.eql(u8, current_digest[0..], embedded_digest[0..])) { + std.debug.warn("U-Boot is up to date. Exiting.\n", .{}); + return 0; + } + + // Erase mtd0 + const mtd0_erasesize = try mtd_info_get_usize("erasesize"); + var erased = 0; + while (erased < mtd0_size) { + //erase page + erased += mtd0_erasesize; + } + // Write mtd0 + + // Verify mtd0 + + std.debug.warn("Done\n", .{}); + return 0; +}