diff --git a/README.md b/README.md index 7de904b..50634f6 100644 --- a/README.md +++ b/README.md @@ -154,8 +154,8 @@ OFFSET TYPE NAME DESCRIPTION 40 u64 nblocks_users 48 u64 nblocks_groupmembers 56 u64 nblocks_additional_gids - 64 u64 getgr_max - 72 u64 getpw_max + 64 u64 getgr_bufsize + 72 u64 getpw_bufsize 80 [48]u8 padding ``` @@ -168,7 +168,7 @@ number of bytes. However, interpreting `[2]u6` with `xxd(1)` is harder than interpreting `[2]u8`. Therefore we are using the space we have to make these integers byte-wide. -`getgr_max` and `getpw_max` is a hint for the caller of `getgr*` and +`getgr_bufsize` and `getpw_bufsize` is a hint for the caller of `getgr*` and `getpw*`-family calls. This is the recommended size of the buffer, so the caller does not receive `ENOMEM`. diff --git a/lib/Corpus.zig b/lib/Corpus.zig index 1ce08c4..ec81dbf 100644 --- a/lib/Corpus.zig +++ b/lib/Corpus.zig @@ -26,8 +26,8 @@ name2group: StringHashMap(u32), group2users: []const []const u32, user2groups: []const []const u32, -getgr_max: usize, -getpw_max: usize, +getgr_bufsize: usize, +getpw_bufsize: usize, pub fn init( baseAllocator: Allocator, @@ -43,15 +43,15 @@ pub fn init( var groups_arr = try allocator.alloc(Group, groupsConst.len); var users_arr = try allocator.alloc(User, usersConst.len); - var getgr_max: usize = 0; + var getgr_bufsize: usize = 0; for (groupsConst) |*group, i| { groups_arr[i] = try group.clone(allocator); - getgr_max = math.max(getgr_max, groups_arr[i].strlenZ()); + getgr_bufsize = math.max(getgr_bufsize, groups_arr[i].strlenZ()); } - var getpw_max: usize = 0; + var getpw_bufsize: usize = 0; for (usersConst) |*user, i| { users_arr[i] = try user.clone(allocator); - getpw_max = math.max(getpw_max, users_arr[i].strlenZ()); + getpw_bufsize = math.max(getpw_bufsize, users_arr[i].strlenZ()); } sort.sort(User, users_arr, {}, cmpUser); @@ -123,8 +123,8 @@ pub fn init( .name2group = name2group, .group2users = group2users, .user2groups = user2groups_final, - .getgr_max = getgr_max, - .getpw_max = getpw_max, + .getgr_bufsize = getgr_bufsize, + .getpw_bufsize = getpw_bufsize, }; } diff --git a/lib/DB.zig b/lib/DB.zig index 796f226..895df9d 100644 --- a/lib/DB.zig +++ b/lib/DB.zig @@ -119,8 +119,8 @@ pub fn fromCorpus( .nblocks_users = nblocks(u64, users.blob), .nblocks_groupmembers = nblocks(u64, groupmembers.blob), .nblocks_additional_gids = nblocks(u64, additional_gids.blob), - .getgr_max = corpus.getgr_max, - .getpw_max = corpus.getpw_max, + .getgr_bufsize = corpus.getgr_bufsize, + .getpw_bufsize = corpus.getpw_bufsize, }; return DB{ @@ -518,7 +518,7 @@ fn nblocks(comptime T: type, arr: []const u8) T { fn assertDefinedLayout(comptime T: type) void { return switch (T) { - u8, u16, u32, u64 => {}, + u4, u8, u16, u32, u64 => {}, else => switch (@typeInfo(T)) { .Array => assertDefinedLayout(meta.Elem(T)), .Pointer => |info| assertDefinedLayout(info.child), @@ -599,7 +599,7 @@ test "high-level API" { defer db.deinit(allocator); // TODO: should accept a buffer instead of an allocator instead. - var buf = try allocator.alloc(u8, db.header.getgr_max); + var buf = try allocator.alloc(u8, db.header.getgr_bufsize); defer allocator.free(buf); const all = try db.getgrnam("all", &buf); try testing.expect(all != null); diff --git a/lib/header.zig b/lib/header.zig index a499ce5..08812f1 100644 --- a/lib/header.zig +++ b/lib/header.zig @@ -7,7 +7,7 @@ const max_shells = @import("shell.zig").max_shells; const magic = [4]u8{ 0xf0, 0x9f, 0xa4, 0xb7 }; const version = 0; -const Endian = enum(u8) { +const Endian = enum(u4) { big, little, @@ -26,12 +26,14 @@ pub const Invalid = error{ InvalidMagic, InvalidVersion, InvalidEndianess, + InvalidPointerSize, }; pub const Header = packed struct { magic: [4]u8 = magic, version: u8 = version, endian: Endian = Endian.native(), + ptr_size: u4 = @sizeOf(?[*:0]const u8), nblocks_shell_blob: u8, num_shells: u8, num_groups: u32, @@ -44,8 +46,8 @@ pub const Header = packed struct { nblocks_users: u64, nblocks_groupmembers: u64, nblocks_additional_gids: u64, - getgr_max: u64, - getpw_max: u64, + getgr_bufsize: u64, + getpw_bufsize: u64, padding: [48]u8 = [1]u8{0} ** 48, pub fn fromBytes(blob: *const [@sizeOf(Header)]u8) Invalid!*const Header { @@ -60,6 +62,12 @@ pub const Header = packed struct { if (self.endian != Endian.native()) return error.InvalidEndianess; + // when ptr size is larger than on the host that constructed it the DB, + // getgr_bufsize/getpw_bufsize may return insufficient values, causing + // OutOfMemory for getgr* and getpw* calls. + if (self.ptr_size < @sizeOf(?[*:0]const u8)) + return error.InvalidPointerSize; + return self; } }; @@ -92,8 +100,8 @@ test "header pack and unpack" { .nblocks_users = 0, .nblocks_groupmembers = 0, .nblocks_additional_gids = 1, - .getgr_max = 16, - .getpw_max = 32, + .getgr_bufsize = 16, + .getpw_bufsize = 32, }; const bytes = mem.asBytes(&header1);