summaryrefslogtreecommitdiff
path: root/src/fs.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs.zig')
-rw-r--r--src/fs.zig29
1 files changed, 29 insertions, 0 deletions
diff --git a/src/fs.zig b/src/fs.zig
index bc35e1cb..d13e36bd 100644
--- a/src/fs.zig
+++ b/src/fs.zig
@@ -213,6 +213,11 @@ pub fn osHandle(p: *pardes.Pardes, req: Req) Reply {
return .{ .tag = req.tag, .payload = .{ .staged = @intCast(out.items.len) } };
},
.read, .write, .setattr => {
+ // A rename or a mode change (`mv`, `chmod`) is refused as not
+ // permitted, EACCES through a mount: /os reads and writes the
+ // files it shows and changes nothing about them.
+ if (req.op == .setattr and (req.set.name or req.set.mode))
+ return tree.failText(req.tag, E.PERM, "permission denied: /os renames nothing and changes no mode");
if (stat.kind != .file) return Reply.fail(req.tag, E.PERM);
var z: [4096]u8 = undefined;
const path_z = std.fmt.bufPrintSentinel(&z, "{s}", .{path}, 0) catch return Reply.fail(req.tag, E.NOENT);
@@ -255,6 +260,30 @@ pub fn validMountName(name: []const u8) bool {
return true;
}
+test "/os refuses a rename or a mode change as not permitted, in words, and still truncates to zero" {
+ if (comptime !pardes.hosted) return error.SkipZigTest;
+ const p = try th.withFile(std.testing.allocator, "x\n");
+ defer p.deinit();
+ var tmp = std.testing.tmpDir(.{});
+ defer tmp.cleanup();
+ try tmp.dir.writeFile(std.testing.io, .{ .sub_path = "kept.txt", .data = "kept\n" });
+ var dir_buf: [4096]u8 = undefined;
+ const dir = dir_buf[0..try tmp.dir.realPath(std.testing.io, &dir_buf)];
+ var node: u64 = os_root;
+ var parts = std.mem.tokenizeScalar(u8, dir, '/');
+ while (parts.next()) |part| node = th.look_up(p, node, part).reply.attr.node;
+ node = th.look_up(p, node, "kept.txt").reply.attr.node;
+ for ([_]Req{
+ .{ .tag = 1, .op = .setattr, .node = node, .set = .{ .mode = true } },
+ .{ .tag = 2, .op = .setattr, .node = node, .set = .{ .name = true }, .data = "moved.txt" },
+ }) |req| {
+ const r = th.call(p, req);
+ try std.testing.expectEqual(E.PERM, r.errno());
+ try std.testing.expectStringStartsWith(r.reply.ename, "permission denied");
+ }
+ try std.testing.expectEqual(tree.Status.ok, th.call(p, .{ .tag = 3, .op = .setattr, .node = node, .truncate = true }).reply.status);
+}
+
test "mounts own their names and dials and reject duplicate or reserved names" {
const gpa = std.testing.allocator;
var ns: Namespace = .{};