A bug with getsockopt(SOL_LOCAL, LOCAL_PEERCRED) ?
Mark Millard
marklmi at yahoo.com
Thu Apr 22 20:33:48 UTC 2021
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
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