safety checks in group parsing

This commit is contained in:
Motiejus Jakštys 2023-06-06 20:37:53 +03:00
parent e1cae43d08
commit a447e7fdf4
4 changed files with 24 additions and 20 deletions

View File

@ -368,21 +368,25 @@ pub fn packCGroup(self: *const DB, group: *const PackedGroup, buf: []u8) error{
}; };
} }
pub fn getGroupByName(self: *const DB, name: []const u8) ?PackedGroup { pub fn getGroupByName(self: *const DB, name: []const u8) error{Overflow}!?PackedGroup {
const idx = bdz.search(self.bdz_groupname, name); const idx = bdz.search(self.bdz_groupname, name);
if (idx >= self.header.num_groups) return null; if (idx >= self.header.num_groups)
return null;
const offset = self.idx_groupname2group[idx]; const offset = self.idx_groupname2group[idx];
const group = PackedGroup.fromBytes(@alignCast(8, self.groups[offset << 3 ..])).group; const group = (try PackedGroup.fromBytes(@alignCast(8, self.groups[offset << 3 ..]))).group;
if (!mem.eql(u8, name, group.name())) return null; if (!mem.eql(u8, name, group.name()))
return null;
return group; return group;
} }
pub fn getGroupByGid(self: *const DB, gid: u32) ?PackedGroup { pub fn getGroupByGid(self: *const DB, gid: u32) error{Overflow}!?PackedGroup {
const idx = bdz.search_u32(self.bdz_gid, gid); const idx = bdz.search_u32(self.bdz_gid, gid);
if (idx >= self.header.num_groups) return null; if (idx >= self.header.num_groups)
return null;
const offset = self.idx_gid2group[idx]; const offset = self.idx_gid2group[idx];
const group = PackedGroup.fromBytes(@alignCast(8, self.groups[offset << 3 ..])).group; const group = (try PackedGroup.fromBytes(@alignCast(8, self.groups[offset << 3 ..]))).group;
if (gid != group.gid()) return null; if (gid != group.gid())
return null;
return group; return group;
} }
@ -393,7 +397,7 @@ pub fn getgrnam(
buf: []u8, buf: []u8,
omit_members: bool, omit_members: bool,
) error{ Overflow, BufferTooSmall }!?CGroup { ) error{ Overflow, BufferTooSmall }!?CGroup {
const group = self.getGroupByName(name) orelse return null; const group = try self.getGroupByName(name) orelse return null;
if (omit_members) if (omit_members)
return try packCGroupNoMembers(&group, buf) return try packCGroupNoMembers(&group, buf)
else else
@ -407,7 +411,7 @@ pub fn getgrgid(
buf: []u8, buf: []u8,
omit_members: bool, omit_members: bool,
) error{ Overflow, BufferTooSmall }!?CGroup { ) error{ Overflow, BufferTooSmall }!?CGroup {
const group = self.getGroupByGid(gid) orelse return null; const group = try self.getGroupByGid(gid) orelse return null;
if (omit_members) if (omit_members)
return try packCGroupNoMembers(&group, buf) return try packCGroupNoMembers(&group, buf)
else else

View File

@ -39,13 +39,11 @@ pub const Entry = struct {
end: usize, end: usize,
}; };
pub fn fromBytes(bytes: []align(8) const u8) Entry { pub fn fromBytes(bytes: []align(8) const u8) error{Overflow}!Entry {
const inner = mem.bytesAsValue(Inner, bytes[0..@sizeOf(Inner)]); const inner = mem.bytesAsValue(Inner, bytes[0..@sizeOf(Inner)]);
const start_blob = @sizeOf(Inner); const start_blob = @sizeOf(Inner);
const end_strings = @sizeOf(Inner) + inner.groupnameLen(); const end_strings = @sizeOf(Inner) + inner.groupnameLen();
const members_offset = compress.uvarint(bytes[end_strings..]) catch |err| switch (err) { const members_offset = try compress.uvarint(bytes[end_strings..]);
error.Overflow => unreachable,
};
const end_blob = end_strings + members_offset.bytes_read; const end_blob = end_strings + members_offset.bytes_read;
return Entry{ return Entry{
@ -70,9 +68,9 @@ pub const Iterator = struct {
total: u32, total: u32,
advanced_by: usize = 0, advanced_by: usize = 0,
pub fn next(it: *Iterator) ?PackedGroup { pub fn next(it: *Iterator) error{Overflow}!?PackedGroup {
if (it.idx == it.total) return null; if (it.idx == it.total) return null;
const entry = fromBytes(@alignCast(8, it.section[it.next_start..])); const entry = try fromBytes(@alignCast(8, it.section[it.next_start..]));
it.idx += 1; it.idx += 1;
it.next_start += entry.end; it.next_start += entry.end;
it.advanced_by = entry.end; it.advanced_by = entry.end;
@ -149,7 +147,7 @@ test "PackedGroup construct" {
var i: u29 = 0; var i: u29 = 0;
var it = PackedGroup.iterator(buf.items, groups.len); var it = PackedGroup.iterator(buf.items, groups.len);
while (it.next()) |group| : (i += 1) { while (try it.next()) |group| : (i += 1) {
try testing.expectEqual(groups[i].gid, group.gid()); try testing.expectEqual(groups[i].gid, group.gid());
try testing.expectEqualStrings(groups[i].name, group.name()); try testing.expectEqualStrings(groups[i].name, group.name());
try testing.expectEqual(groups[i].members_offset, group.membersOffset()); try testing.expectEqual(groups[i].members_offset, group.membersOffset());

View File

@ -369,7 +369,9 @@ fn getgrent_r(
return c.NSS_STATUS_UNAVAIL; return c.NSS_STATUS_UNAVAIL;
}); });
const group = it.next() orelse { const group = it.next() catch |err| switch (err) {
error.Overflow => return badFile(errnop),
} orelse {
errnop.* = 0; errnop.* = 0;
return c.NSS_STATUS_NOTFOUND; return c.NSS_STATUS_NOTFOUND;
}; };

View File

@ -159,7 +159,7 @@ fn group(stdout: anytype, db: *const DB, keys: []const [*:0]const u8) error{Over
for (keys) |key| { for (keys) |key| {
const keyZ = mem.span(key); const keyZ = mem.span(key);
const maybe_packed_group = if (fmt.parseUnsigned(u32, keyZ, 10)) |gid| const maybe_packed_group = try if (fmt.parseUnsigned(u32, keyZ, 10)) |gid|
db.getGroupByGid(gid) db.getGroupByGid(gid)
else |_| else |_|
db.getGroupByName(keyZ); db.getGroupByName(keyZ);
@ -178,7 +178,7 @@ fn group(stdout: anytype, db: *const DB, keys: []const [*:0]const u8) error{Over
fn groupAll(stdout: anytype, db: *const DB) error{Overflow}!u8 { fn groupAll(stdout: anytype, db: *const DB) error{Overflow}!u8 {
var it = PackedGroup.iterator(db.groups, db.header.num_groups); var it = PackedGroup.iterator(db.groups, db.header.num_groups);
while (it.next()) |g| while (try it.next()) |g|
if (try printGroup(stdout, db, &g)) |exit_code| if (try printGroup(stdout, db, &g)) |exit_code|
return exit_code; return exit_code;