A bug with getsockopt(SOL_LOCAL, LOCAL_PEERCRED) ?

Mark Millard marklmi at yahoo.com
Thu Apr 22 20:47:59 UTC 2021


On 2021-Apr-22, at 13:33, Mark Millard <marklmi at yahoo.com> wrote:

> On 2021-Apr-22, at 12:34, Konstantin Belousov <kostikbel at gmail.com> wrote:
> 
>> On Thu, Apr 22, 2021 at 09:49:15PM +0300, Gleb Popov wrote:
>>> On Thu, Apr 22, 2021 at 1:33 PM Konstantin Belousov <kostikbel at gmail.com>
>>> wrote:
>>> 
>>>> There is no peer for listening socket.
>>>> 
>>>> Show minimal code that works for you on Linux.
>>>> 
>>> 
>>> Here you go: http://arrowd.name/un_linux.cpp
>>> It is almost identical to FreeBSD one, but works for me on ArchLinux.
>> 
>> Of course it works because it uses s2, that is, connected and not listening
>> socket, for getsockopt(), same as the working FreeBSD version.
> 
> I made a variant that tries s2 and then s, printing the
> peercred uid, group id, and pid fields, and built it on
> Fedora 34. The result was:
> 
> # ./a.out & ncat -U foobar
> [1] 18646
> s2 data is uid field: 0 groups[0] field: 0 pid field: 18647
> s data is uid field: 0 groups[0] field: 0 pid field: 18646
> [1]+  Done                    ./a.out

As a cross check, I also tried building and running on
ubuntu 2021.04 (so debian basead, vs. red hat based before):

# ./a.out & nc -U foobar
[1] 39348
s2 data is uid field: 0 groups[0] field: 0 pid field: 39349
s data is uid field: 0 groups[0] field: 0 pid field: 39348
[1]+  Done                    ./a.out

So two major branches of Linux based systems seem to
agree for the issue.

I do not have any other variants around to quickly check.
The tests were all on aarch64, by the way.

> On FreeBSD:
> 
> # ./a.out & nc -U foobar
> s2 data is uid field: 0 groups[0] field: 0 pid field: 6984
> getsockopt for s
> failed with
> Socket is not connected
> [1]   Done                    ./a.out
> 
> The code is:
> 
> #ifndef __FreeBSD__
> #define _GNU_SOURCE
> #endif
> 
> #include <stdio.h>
> #include <stdlib.h>
> #include <errno.h>
> #include <string.h>
> #include <unistd.h>
> 
> #include <sys/types.h>
> 
> #ifdef __FreeBSD__
> #define FOR_PEERCRED    0
> #define CR_GROUP_ID     cr_groups[0]
> #else // Linux
> #define xucred          ucred
> #define FOR_PEERCRED    SOL_SOCKET
> #define LOCAL_PEERCRED  SO_PEERCRED
> #define cr_uid          uid
> #define CR_GROUP_ID     gid
> #define cr_pid          pid
> #endif
> 
> #include <sys/socket.h>
> #include <sys/un.h>
> #ifdef __FreeBSD__
> #include <sys/ucred.h>
> #endif
> #include <netinet/in.h>
> #include <netinet/tcp.h>
> 
> 
> void failure(char const * err)
> {
>    puts(err);
>    puts("failed with");
>    puts(strerror(errno));
> }
> 
> void die(char const * err)
> {
>    failure(err);
>    unlink("foobar");
>    exit(1);
> }
> 
> int main()
> {
>    int s = socket(PF_LOCAL, SOCK_STREAM, 0);
>    if(s < 0) die("socket");
> 
>    struct sockaddr_un addrunix;
>    memset(&addrunix, 0, sizeof(addrunix));
>    addrunix.sun_family = AF_UNIX;
>    memcpy(addrunix.sun_path, "foobar", 6);
> 
>    int r = bind(s, (const struct sockaddr *)&addrunix, sizeof(struct sockaddr_un));
>    if(r < 0) die("bind");
> 
>    listen(s, 64);
> 
>    int s2;
>    do
>    {
>        s2 = accept4(s, 0, 0, 0);
>    } while (s2 < 0 && errno == EAGAIN);
>    if(s2 < 0) die("accept4");
> 
>    struct xucred s2_creds;
>    socklen_t s2_credSize = sizeof(struct xucred);
>    r = getsockopt(s2, FOR_PEERCRED, LOCAL_PEERCRED, &s2_creds, &s2_credSize);
>    if(r < 0) failure("getsockopt for s2");
>    else
>        printf("s2 data is uid field: %jd groups[0] field: %jd pid field: %jd\n",
>           (uintmax_t) s2_creds.cr_uid, (uintmax_t) s2_creds.CR_GROUP_ID, (uintmax_t) s2_creds.cr_pid);
> 
>    struct xucred s_creds;
>    socklen_t s_credSize = sizeof(struct xucred);
>    r = getsockopt(s, FOR_PEERCRED, LOCAL_PEERCRED, &s_creds, &s_credSize);
>    if(r < 0) failure("getsockopt for s");
>    else
>        printf("s data is uid field: %jd groups[0] field: %jd pid field: %jd\n",
>           (uintmax_t) s_creds.cr_uid, (uintmax_t) s_creds.CR_GROUP_ID, (uintmax_t) s_creds.cr_pid);
> 
>    unlink("foobar");
>    return 0;
> }
> 
> 




===
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)



More information about the freebsd-hackers mailing list