On Fri, Dec 1, 2023 at 11:08 PM Kuniyuki Iwashima <kuniyu@xxxxxxxxxx> wrote: > > From: Alejandro Colomar <alx@xxxxxxxxxx> > Date: Fri, 1 Dec 2023 13:54:39 +0100 > > Hello Alexey, > > > > On Fri, Dec 01, 2023 at 01:16:27PM +0100, Alexey Tikhonov wrote: > > > Hello. > > > > > > There is a discrepancy between the man page description of > > > 'SO_PEERCRED' and real behavior. > > > > > > `man 7 unix` states: > > > ``` > > > SO_PEERCRED > > > This read-only socket option returns the credentials of > > > the peer process connected to this socket. The returned > > > credentials are those that were in effect at the time of > > > the call to connect(2) or socketpair(2). > > > ``` > > > > > > This doesn't match real behavior in following situation (just an example): > > > - process starts with uid=0, gid=0 > > > - process creates UNIX socket, binds it, listens on it > > > - process changes to uid=uid1, git=gid1 (using `setresuid()`, `setresgid()`) > > > - another process connects to the listening socket and requests > > > peer's credentials using `getsockopt(... SOL_SOCKET, SO_PEERCRED ...)` > > > > > > According to the man page: SO_PEERCRED should report (uid1, gid1), > > > because peer process was running under (uid1, gid1) "at the time of > > > the call to connect(2)" > > > In reality SO_PEERCRED reports (0, 0) > > > Reproducing code is available in > > > https://bugzilla.redhat.com/show_bug.cgi?id=2247682 > > > > > > I'm not entirely sure if this is a real bug or rather a poor > > > description in the man page, but I tend to think that it's the latter. > > When calling getsockopt(), we cannot know dynamically who the peer's > owner is. So, we just initialise the cred when we know the owner, > and it's the caller of listen(), connect(), and socketpair(). > > In your case, the listener's cred is initialised with the caller's > cred during the first liten(). > > listener's peer_cred = get_cred(rcu_dereference_protected(current->cred, 1)) Thank you for the explanation. So this is an omission in the man page. > > And connect() will initialise two creds as follows: > > connect()er's peer_cred = listener's peer_cred > new socket's peer_cred = get_cred(rcu_dereference_protected(current->cred, 1)) > > If you call listen() again after setresuid() and before connect(), > you can update the listener's cred and get the new IDs at the final > getsockopt(). >