{"action":"created","issue":{"url":"https://api.github.com/repos/haskell/network/issues/308","repository_url":"https://api.github.com/repos/haskell/network","labels_url":"https://api.github.com/repos/haskell/network/issues/308/labels{/name}","comments_url":"https://api.github.com/repos/haskell/network/issues/308/comments","events_url":"https://api.github.com/repos/haskell/network/issues/308/events","html_url":"https://github.com/haskell/network/issues/308","id":297697424,"number":308,"title":"The peer cred tests are not portable","user":{"login":"kazu-yamamoto","id":165387,"avatar_url":"https://avatars3.githubusercontent.com/u/165387?v=4","gravatar_id":"","url":"https://api.github.com/users/kazu-yamamoto","html_url":"https://github.com/kazu-yamamoto","followers_url":"https://api.github.com/users/kazu-yamamoto/followers","following_url":"https://api.github.com/users/kazu-yamamoto/following{/other_user}","gists_url":"https://api.github.com/users/kazu-yamamoto/gists{/gist_id}","starred_url":"https://api.github.com/users/kazu-yamamoto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kazu-yamamoto/subscriptions","organizations_url":"https://api.github.com/users/kazu-yamamoto/orgs","repos_url":"https://api.github.com/users/kazu-yamamoto/repos","events_url":"https://api.github.com/users/kazu-yamamoto/events{/privacy}","received_events_url":"https://api.github.com/users/kazu-yamamoto/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-02-16T07:04:17Z","updated_at":"2018-02-16T07:33:39Z","closed_at":null,"author_association":"COLLABORATOR","body":"@vdukhovni pointed out:\r\n\r\nThese tests don't behave as expected on FreeBSD, returning no\r\ncredentials for a socketpair(), and surprisingly returning some\r\nsort of credential for an unbound AF_INET socket!"},"comment":{"url":"https://api.github.com/repos/haskell/network/issues/comments/366163371","html_url":"https://github.com/haskell/network/issues/308#issuecomment-366163371","issue_url":"https://api.github.com/repos/haskell/network/issues/308","id":366163371,"user":{"login":"vdukhovni","id":1107986,"avatar_url":"https://avatars2.githubusercontent.com/u/1107986?v=4","gravatar_id":"","url":"https://api.github.com/users/vdukhovni","html_url":"https://github.com/vdukhovni","followers_url":"https://api.github.com/users/vdukhovni/followers","following_url":"https://api.github.com/users/vdukhovni/following{/other_user}","gists_url":"https://api.github.com/users/vdukhovni/gists{/gist_id}","starred_url":"https://api.github.com/users/vdukhovni/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vdukhovni/subscriptions","organizations_url":"https://api.github.com/users/vdukhovni/orgs","repos_url":"https://api.github.com/users/vdukhovni/repos","events_url":"https://api.github.com/users/vdukhovni/events{/privacy}","received_events_url":"https://api.github.com/users/vdukhovni/received_events","type":"User","site_admin":false},"created_at":"2018-02-16T07:33:39Z","updated_at":"2018-02-16T07:33:39Z","author_association":"NONE","body":"Note that FreeBSD does not have SO_PEERCRED, but in `man 4 unix` we have:\r\n```\r\n     LOCAL_PEERCRED      Requested via getsockopt(2) on a SOCK_STREAM socket\r\n                         returns credentials of the remote side.  These will\r\n                         arrive in the form of a filled in xucred structure,\r\n                         defined in <sys/ucred.h> as follows:\r\n\r\n                         struct xucred {\r\n                           u_int cr_version;             /* structure layout version */\r\n                           uid_t cr_uid;                 /* effective user id */\r\n                           short cr_ngroups;             /* number of groups */\r\n                           gid_t cr_groups[XU_NGROUPS];  /* groups */\r\n                         };\r\n                         The cr_version fields should be checked against\r\n                         XUCRED_VERSION define.\r\n\r\n                         The credentials presented to the server (the\r\n                         listen(2) caller) are those of the client when it\r\n                         called connect(2); the credentials presented to the\r\n                         client (the connect(2) caller) are those of the\r\n                         server when it called listen(2).  This mechanism is\r\n                         reliable; there is no way for either party to\r\n                         influence the credentials presented to its peer\r\n                         except by calling the appropriate system call (e.g.,\r\n                         connect(2) or listen(2)) under different effective\r\n                         credentials.\r\n\r\n                         To reliably obtain peer credentials on a SOCK_DGRAM\r\n                         socket refer to the LOCAL_CREDS socket option.\r\n```\r\nor alternatively in `man 3 getpeereid`:\r\n```\r\nSYNOPSIS\r\n     #include <sys/types.h>\r\n     #include <unistd.h>\r\n\r\n     int\r\n     getpeereid(int s, uid_t *euid, gid_t *egid);\r\n\r\nDESCRIPTION\r\n     The getpeereid() function returns the effective user and group IDs of the\r\n     peer connected to a UNIX-domain socket.  The argument s must be a\r\n     UNIX-domain socket (unix(4)) of type SOCK_STREAM on which either\r\n     connect(2) or listen(2) have been called.  The effective used ID is\r\n     placed in euid, and the effective group ID in egid.\r\n```\r\nbut the text explicitly restricts this to bound/connected sockets, and socketpair() does not qualify.\r\nLikely a test with an actual bound server socket and a connected client would work for the AF_UNIX part of the tests.  As to why getpeereid() returns garbage for AF_INET, the implementation of `getpeerid()` is just a wrapper around the above `LOCAL_PEERCRED` socket option:\r\n```\r\ngetpeereid(int s, uid_t *euid, gid_t *egid)\r\n{\r\n        struct xucred xuc;\r\n        socklen_t xuclen;\r\n        int error;\r\n\r\n        xuclen = sizeof(xuc);\r\n        error = _getsockopt(s, 0, LOCAL_PEERCRED, &xuc, &xuclen);\r\n        if (error != 0)\r\n                return (error);\r\n        if (xuc.cr_version != XUCRED_VERSION)\r\n                return (EINVAL);\r\n        *euid = xuc.cr_uid;\r\n        *egid = xuc.cr_gid;\r\n        return (0);\r\n}\r\n```\r\nNote that the `level' is 0, which means different things for different socket types.  Thus in particular we have:\r\n```\r\nnetinet/in.h:#define     IPPROTO_IP              0               /* dummy for IP */\r\nnetinet/in.h:#define     IP_OPTIONS              1    /* buf/ip_opts; set/get IP options */\r\nsys/un.h:#define LOCAL_PEERCRED          1       /* retrieve peer credentials */\r\n```\r\nSo the same `getsockopt()` call that retrieves peer credentials for `AF_UNIX` sockets happens to retrieve `IP_OPTIONS` for INET sockets.  That's why the AF_INET variant is not failing \"as expected\".\r\n\r\nIt is simply NOT VALID to call getpeereid() on sockets of the wrong type,  but libc does not check (perhaps it should), but the application is responsible for not doing that.\r\n\r\nSo at least the AF_INET failure test needs to go, and the AF_UNIX success test should test real bound/connected sockets not a socketpair()."}}
{"actor":{"display_login":"vdukhovni"}}