[GSOC 2023] .NET Port

Code that would have relied on process_vm_[read/write]v on Linux, or some kind of IPC using transfer_area but without being bound to areas.

There is an example of usage for this functionality in this commit; check for the code where mmap is called with MAP_REMAP and the second last argument is non-zero.

        void* page = mmap(NULL, pageSize, PROT_READ, MAP_PRIVATE | MAP_REMAP, handle, (off_t)addressAligned);

Yes and no. Usage of this syscall is guarded by an euid check. If the euid is 0 it can be used on any team (except B_SYSTEM_TEAM). Otherwise, the euid of both the source and target teams must match the caller’s euid. This is the same check as Haiku’s _kern_install_team_debugger syscall.

In the patch I have included a test asserting that this function should fail for a child process after dropping its root privileges.

I think we shouldn’t allow this even when euids match, it’s just too powerful. It should instead check B_CLONEABLE_AREA permissions, as functionally that’s what it’s doing.

Perhaps that also suggests the proper name for this function: clone_memory (as opposed to just clone_area.)

Without this syscall we can already arbitrarily read, write, and otherwise modify the address space of any team by using debugger APIs. Having a new call that is as restrictive as _kern_install_team_debugger should not cause any security issues.

clone_area, on the other hand, seems to work on any userland area, regardless of the target area’s owner’s euid. Therefore, the B_CLONEABLE_AREA flag is needed.

Maybe, I will change it to clone_memory (and the corresponding flag, MAP_CLONE).

I am not sure that double mapper is actually useful on Haiku. It do not affect functionality, but waste resources. Security benefits are also suspicious. On 32 bit virtual address space waste may be serious problem.

And those should probably check that you are UID 0 before allowing arbitrary debugger attachments. The fact that basically everything runs as UID 0 at present makes this check moot most of the time. Nonetheless we should have it.

For now. It used to not be required at all, and you could clone anything. More restrictions should get added in the future, probably.

I think we shouldn’t have an extension mmap flag at all, and have a completely separate function be the only way to do this.

But I also agree with this. I really think we should just set WriteXorExecute=0 and quit worrying about it.

Directly quoting Haiku source code:

_user_install_team_debugger(team_id teamID, port_id debuggerPort)
	if (geteuid() != 0 && team_geteuid(teamID) != geteuid())

	return install_team_debugger(teamID, debuggerPort, -1, false, false);

The nub thread seems to conduct no additional checks.

This is only one of the functionalities of this syscall. The main (and required) functionality is related to committing memory.

This port does not intend to support 32-bit anyway. Also, if it works on 32-bit Linux, why won’t it work here?

I’m not disputing that you are correct as to how it currently behaves, I’m talking about how things should behave more ideally.

That seems like we should accomplish it a different way other than performing “clone” operations every time we need to commit something…

You might want to look at how ptrace and process_vm_readv checks on Linux then. Apart from the euid check, depending on the system setting, these two syscall additionally requires the caller process to be an ancestor of the target.

If you don’t like this centralized vm_remap-style API, then might it be better if I implemented process_vm_readv, FreeBSD mremap and a custom commit_memory instead?

For the debugger, applications should be able to protect themselves, for example by using disable_debugger/enable_debugger (I don’t know if that already works, but it sounds like these should protect from attaching a debugger).

So, the fact that a security problem exists with this is not a reason to open an even wider security problem.


Applications should be not able to protect themself against system administrator.

1 Like

Maybe do what Linux does then? Either the caller must be root or an ancestor of the target, if you think the euid check is inadequate.

I remember plenty of tricks in Windows applications, to prevent debugging with SoftICE.

Had a go at porting just that today, however, there is some bug with GitHub - realm/realm-core: Core database component for the Realm Mobile Database SDKs, so I gave up.

I might pick this up again one day if the HaikuPorts folks ported this thing to Haiku (compilation is trivial, but there are some tricky bugs somewhere).

FNA is working:

Using a sample here: FNA.Examples/DrawACube at main · danielcrenna/FNA.Examples · GitHub

There are some native components, but these can build on Haiku without any patches; the only thing needed is for someone to write up a recipe for those and all FNA games can run unmodified.


I think it has some potential legitimate usages (e.g. implementing drivers in userland), but probably not broad usage, no.

Actually there are some parts of the kernel that might benefit from this (IO routines handling userspace buffers which presently use either lock_memory or clone_area for example.)

If we both agree that it might be useful, then this patch should be eventually merged, shouldn’t it (not trying to rush the review process or anything, just trying to say that it should not be completely rejected)?

On the CoreCLR side, in the end it’s the people at dotnet who ultimately decides whether some code/an approach is acceptable or not.

Well that was quick! Fantastic work!

using Haiku.App;
using Haiku.Interface;

public class Test : BApplication
    private BWindow _window;

    public Test() : base("application/x-vnd.Test")
        _window = new BWindow(new BRect(100, 100, 300, 300), "Test", WindowType.B_TITLED_WINDOW, 0, 0);

    public static void Main()
        var application = new Test();

What do you think of this kind of programming?

This is the current state of Haiku C# API bindings, generated using CppSharp by Mono.

There are a few issues related to the native portion of the bindings (a special shared library that is created in order to keep inlined functions alive), so the thing isn’t working correctly at runtime yet.



Got this tiny test window