diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.zig | 16 | ||||
| -rw-r--r-- | src/ninep/ctl.zig | 18 | ||||
| -rw-r--r-- | src/pardes.zig | 7 |
3 files changed, 35 insertions, 6 deletions
diff --git a/src/config.zig b/src/config.zig index b6eb4520..cc46adfc 100644 --- a/src/config.zig +++ b/src/config.zig @@ -1148,8 +1148,18 @@ pub const Runtime = struct { if (percent > 100) return false; state.window_blur = percent; }, - // Bare, it returns to the default directory. - .dump_dir => if (!state.dump_dir.set(std.mem.trim(u8, argument orelse "", " \t\r\n"))) return false, + // Bare, it returns to the default directory. Else an absolute or + // `~` path, to a directory there or to be made, that may be + // written: a Dump there could never be, refused now. + .dump_dir => { + const text = std.mem.trim(u8, argument orelse "", " \t\r\n"); + if (text.len > 0) { + if (text[0] != '/' and text[0] != '~') return false; + var home_buf: [4096]u8 = undefined; + if (pardes.filesystem.deniedAbove(pardes.filesystem.expandHome(text, &home_buf))) return false; + } + if (!state.dump_dir.set(text)) return false; + }, .message_ms => |which| { const text = std.mem.trim(u8, argument orelse return false, " \t\r\n"); for (text) |byte| if (!std.ascii.isDigit(byte)) return false; @@ -1267,7 +1277,7 @@ pub const Runtime = struct { .tagline_size => std.fmt.comptimePrint("{d}-{d} (a percentage)", .{ tagline_percent_min, tagline_percent_max }), .message_ms => std.fmt.comptimePrint("0-{d} (milliseconds)", .{message_ms_max}), .shell => "a path of at most 255 bytes; bare, $SHELL, else /bin/sh", - .dump_dir => std.fmt.comptimePrint("a path of at most {d} bytes; bare, the default", .{limits.host_path_cap}), + .dump_dir => std.fmt.comptimePrint("an absolute or ~ path of at most {d} bytes, to a directory that may be written; bare, the default", .{limits.host_path_cap}), .shader => "a Shadertoy file's path, or off", .font => "a name or path, :8 to :72 after it (Mono:14)", else => null, diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index 89c2e5dd..d4d09e0b 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -2332,8 +2332,9 @@ test "a Restore of a file that is no dump fails the write before any warning, an try testing.expect(p.panes[0].?.discard_warned == null); p.fs.late_failure_len = 0; - p.dumpFailed("/nowhere/pardes.dump.zon", error.FileNotFound); - try testing.expectEqualStrings("Dump /nowhere/pardes.dump.zon: no such directory", p.fs.late_failure[0..p.fs.late_failure_len]); + // (Under /tmp: under / a user's Dump is refused permission, not missing.) + p.dumpFailed("/tmp/pardes-nowhere-zz/pardes.dump.zon", error.FileNotFound); + try testing.expectEqualStrings("Dump /tmp/pardes-nowhere-zz/pardes.dump.zon: no such directory", p.fs.late_failure[0..p.fs.late_failure_len]); // A DumpDir that is there but no directory says that. p.fs.late_failure_len = 0; p.dumpFailed("/dev/null/pardes.dump.zon", error.NotDir); @@ -4357,3 +4358,16 @@ test "a ctl line over 1 MiB is refused once, EINVAL, and its tail is not run as try testing.expectEqualStrings("", pane_files.fileOf(p.panes[0].?).?.content); _ = call(p, .{ .tag = 4, .op = .release, .node = node, .handle = h }); } + +test "DumpDir refuses a relative directory and one that may not be written, up front; a Dump there says permission denied" { + if (comptime !pardes.hosted) return; + const p = try withFile(testing.allocator, "x\n"); + defer p.deinit(); + const root_ctl = @intFromEnum(tree.TopFile.ctl); + try testing.expectEqual(E.INVAL, wr(p, root_ctl, "DumpDir dumps\n").errno()); + try testing.expectEqual(E.INVAL, wr(p, root_ctl, "DumpDir /proc/1/root/dumps\n").errno()); + try testing.expectEqual(Status.ok, wr(p, root_ctl, "DumpDir /tmp/pardes-dumps-test\n").reply.status); + p.fs.late_failure_len = 0; + p.dumpFailed("/proc/1/root/x/pardes.dump.zon", error.FileNotFound); + try testing.expect(std.mem.endsWith(u8, p.fs.late_failure[0..p.fs.late_failure_len], ": permission denied")); +} diff --git a/src/pardes.zig b/src/pardes.zig index 2b0ed8f0..dbb37084 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -5563,7 +5563,12 @@ pub const Pardes = struct { const parent = std.fs.path.dirname(path) orelse "/"; const kind: ?std.Io.File.Kind = if (comptime hosted) (if (filesystem.localPath(parent)) |local| exec.kindOf(local) else .directory) else .directory; const no_dir = err == error.FileNotFound or err == error.NotDir or kind != .directory; - if (kind != null and kind != .directory) { + // Not there because one above refuses: that is why, EACCES. + const denied = no_dir and kind == null and (if (comptime hosted) (if (filesystem.localPath(parent)) |local| filesystem.deniedAbove(local) else false) else false); + if (denied) { + var said: [limits.host_path_cap + 48]u8 = undefined; + p.reportFailure(p.active, std.fmt.bufPrint(&said, "{s}: permission denied", .{operation}) catch "Dump: permission denied"); + } else if (kind != null and kind != .directory) { var said: [limits.host_path_cap + 48]u8 = undefined; p.reportFailure(p.active, std.fmt.bufPrint(&said, "{s}: {s} is not a directory", .{ operation, parent }) catch "Dump: not a directory"); } else if (no_dir) { |
