Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any way to set uid in dbus authentication? #443

Closed
YJDoc2 opened this issue Jun 28, 2023 · 6 comments
Closed

Any way to set uid in dbus authentication? #443

YJDoc2 opened this issue Jun 28, 2023 · 6 comments

Comments

@YJDoc2
Copy link

YJDoc2 commented Jun 28, 2023

Hello, thanks for your efforts on this library!

I was wondering if there is any way we can set the uid when authenticating with dbus using this library?
Specifically, we are using this to communicate with dbus in youki , and we are currently trying to work on running rootless containers with podman. One of the issues we are facing when connecting to dbus, is that when creating a session dbus client, we use

Client::new_session().context("failed to create session dbus client")?

This call fails and thus the whole process fails. We debugged this, and reached to this analysis, which in short is this :

  • when running as root, youki creates a dbus client, and all works well.
  • However, when running rootless under podman specifically, podman creates a user namespace and launches youki in it as root user of that namespace.
  • But in that case when youki tries to connect to dbus, there is a mismatch in actual uid and uid that is used for dbus auth, and so it fails in that step. At least that's what we currently think as per the above comment.
  • The reason for this mismatch as we think right now is that
    • the user starts podman as non root user say uid 1000
    • podman then creates a new user namespace and launches youki process into that, through user 0 in that namespace
    • when dbus-rs calls get-uid in the new_session, it gets 0, but the whole process (podman+youki) is owned by user 1000 so the actual uid and uid used for auth is mismatched

Is there any way either currently or with changes that we can specify uid for this? I tried to look into dbus-rs code and code of runc, and this is what I have figured out so far.

Thanks for help :)

@diwic
Copy link
Owner

diwic commented Jun 29, 2023

Can you use the seteuid function to switch user temporarily?

@YJDoc2
Copy link
Author

YJDoc2 commented Jul 3, 2023

Hey @diwic Thanks a lot for the suggestion! I tried it out and it partially worked, but I'm still running into some issues.

First of all, I found out that we don't need just a new private connection, but a private connection to a specific bus address, so I changed the code for that. After that I tried using setuid, but I'm running into some problems .

The code I'm using is :

let current_uid = nix::unistd::getuid();
        
let mut channel = Channel::open_private("unix:path=/run/user/1000/bus")?;

nix::unistd::setuid(new_uid.into()).unwrap();
channel.register()?;
nix::unistd::setuid(current_uid).unwrap();

let conn: dbus::blocking::Connection = channel.into();

here the new_uid is what the authentication uid should be, i.e the uid of non-root user who is launching the container process. The bus address is currently hardcoded, and will be passed in as param later, but I have verified that runc also uses the same one when running rootless.

The issues I'm running into are :

  • When I run this, I get error of permission denied while connecting to socket.
systemd error: dbus error: Failed to connect to socket /run/user/1000/bus: Permission denied
  • Secondly, I'm not able to reset the uid after the register call (I tested this by commenting it out). As I have changed uid to non-root user, I think it prevents me from changing back to root.

I checked the permission to the socket path, and it is srw-rw-rw , so even user id 1000 should be able to connect to it.

@diwic
Copy link
Owner

diwic commented Jul 5, 2023

Secondly, I'm not able to reset the uid after the register call (I tested this by commenting it out). As I have changed uid to non-root user, I think it prevents me from changing back to root.

Try using seteuid, not setuid. Does this make a difference? If not I guess we're out of luck here.

@YJDoc2
Copy link
Author

YJDoc2 commented Jul 13, 2023

Hey @diwic Thanks for help. I tried seteuid, and that doesn't work as well. I did a little digging , and the core issue seems to be with libdubs / dbus server itself. I tried stracing with stack trace, and even with using Channel::new_session or Channel::use_private , the actual authentication call originates from dbus (which, in hind-sight should have been obvious to me, as this crate uses ffi for that 😅 ).

The issue is : dbus as a spec, supports various auth methods, including external which we are using. As per spec, we can either provide a uid OR let the dbus server directly query it from kernel and assume that uid to be valid. However, in many implementations of dbus servers (especially older versions) the second option is not valid, i.e. caller must supply uid, otherwise the request is invalid. To comply with this many of the client libraries call getuid and pass that automatically as the uid for auth. I suspect that because it is a shared library and our call originates from a namespaced context (i.e. from inside a container) the getuid call (or geteuid call, whichever is used by the client library) gets it as 0, which is valid in the container context. At least this is my suspicion, otherwise with setuid or seteuid, this should have worked.

I also saw that this crate has code for native implementation of auth, but that feature is turned off as not yet ready. If I understand correctly, then external auth means that validate the connection itself at the time of connecting, and accept communication from that as authorized. If so, is there any way where we (youki) can own the initial authentication, and pass something (socket, some fd etc) to this crate, which will convert it to Channel, without running auth? Right now, I'm probably thinking of copying the code in this crate for native auth for that ; if that would be possible.

@diwic
Copy link
Owner

diwic commented Jul 13, 2023

Since the libdbus code seems to use geteuid (see dbus-sysdeps-unix.c) I would have assumed seteuid would have helped it to get the id you want it to.

Anyhow, since this is out of my control, I think you might have better luck with zbus if the maintainer there is responsive. Or talk to libdbus upstream.

@YJDoc2
Copy link
Author

YJDoc2 commented Aug 1, 2023

Hey sorry to keep this open. For anyone who comes looking later, the gist is :
You can use seteuid call to temp change the uid, iff you want to connect to system/session bus. It didn't work in my case because I wanted to connect to a different bus, and uid I need for bus connection is different from uid I need for authentication.

See youki-dev/youki#2208 for a detailed discussion of this we did on youki.

Thanks diwic for quickly replying and helping out 🙏

@YJDoc2 YJDoc2 closed this as completed Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants