A bug with getsockopt(SOL_LOCAL, LOCAL_PEERCRED) ?
Mark Millard
marklmi at yahoo.com
Thu Apr 22 20:59:35 UTC 2021
[This is not about what Konstantin was asking about, but
about other details. Avoiding the irrelevant material
in the TO/CC.]
On 2021-Apr-22, at 13:47, Mark Millard <marklmi at yahoo.com> wrote:
> 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
>
So s2 gets the pid of the ncat and s gets the pid of a.out.
Is that what you expected?
> 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 s2 gets the pid of the nc and s gets the pid of a.out.
Same question applies.
> 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
Were you expecting s2 to get the pid of nc and
s to get the pid of a.out under FreeBSD as well?
Would that be getting what you want?
>> 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