1 /* 2 * Check decoding of SO_PEERCRED socket option. 3 * 4 * Copyright (c) 2017 Dmitry V. Levin <ldv@altlinux.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "tests.h" 31 32 #include <stddef.h> 33 #include <stdio.h> 34 #include <sys/socket.h> 35 #include <unistd.h> 36 37 #include "print_fields.h" 38 39 static const char *errstr; 40 41 static int 42 get_peercred(int fd, void *val, socklen_t *len) 43 { 44 int rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, val, len); 45 errstr = sprintrc(rc); 46 return rc; 47 } 48 49 int 50 main(void) 51 { 52 TAIL_ALLOC_OBJECT_CONST_PTR(struct ucred, peercred); 53 TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len); 54 55 int sv[2]; 56 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) 57 perror_msg_and_skip("socketpair AF_UNIX SOCK_STREAM"); 58 59 /* classic getsockopt */ 60 *len = sizeof(*peercred); 61 get_peercred(sv[0], peercred, len); 62 printf("getsockopt(%d, SOL_SOCKET, SO_PEERCRED", sv[0]); 63 PRINT_FIELD_D(", {", *peercred, pid); 64 PRINT_FIELD_UID(", ", *peercred, uid); 65 PRINT_FIELD_UID(", ", *peercred, gid); 66 printf("}, [%d]) = %s\n", *len, errstr); 67 68 int fd = socket(AF_UNIX, SOCK_STREAM, 0); 69 if (fd < 0) 70 perror_msg_and_skip("socket AF_UNIX SOCK_STREAM"); 71 72 /* getsockopt with optlen larger than necessary - shortened */ 73 *len = sizeof(*peercred) + 1; 74 get_peercred(fd, peercred, len); 75 printf("getsockopt(%d, SOL_SOCKET, SO_PEERCRED", fd); 76 PRINT_FIELD_D(", {", *peercred, pid); 77 PRINT_FIELD_UID(", ", *peercred, uid); 78 PRINT_FIELD_UID(", ", *peercred, gid); 79 printf("}, [%u->%d]) = %s\n", 80 (unsigned int) sizeof(*peercred) + 1, *len, errstr); 81 82 /* getsockopt with optlen smaller than usual - truncated to ucred.pid */ 83 *len = sizeof(peercred->pid); 84 get_peercred(fd, peercred, len); 85 printf("getsockopt(%d, SOL_SOCKET, SO_PEERCRED", fd); 86 PRINT_FIELD_D(", {", *peercred, pid); 87 printf("}, [%d]) = %s\n", *len, errstr); 88 89 /* getsockopt with optlen smaller than usual - truncated to ucred.uid */ 90 *len = offsetof(struct ucred, gid); 91 get_peercred(fd, peercred, len); 92 printf("getsockopt(%d, SOL_SOCKET, SO_PEERCRED", fd); 93 PRINT_FIELD_D(", {", *peercred, pid); 94 PRINT_FIELD_UID(", ", *peercred, uid); 95 printf("}, [%d]) = %s\n", *len, errstr); 96 97 /* getsockopt with optlen larger than usual - truncated to raw */ 98 *len = sizeof(*peercred) - 1; 99 get_peercred(fd, peercred, len); 100 printf("getsockopt(%d, SOL_SOCKET, SO_PEERCRED, ", fd); 101 print_quoted_hex(peercred, *len); 102 printf(", [%d]) = %s\n", *len, errstr); 103 104 /* getsockopt optval EFAULT */ 105 *len = sizeof(*peercred); 106 get_peercred(fd, &peercred->uid, len); 107 printf("getsockopt(%d, SOL_SOCKET, SO_PEERCRED, %p, [%d]) = %s\n", 108 fd, &peercred->uid, *len, errstr); 109 110 /* getsockopt optlen EFAULT */ 111 get_peercred(fd, peercred, len + 1); 112 printf("getsockopt(%d, SOL_SOCKET, SO_PEERCRED, %p, %p) = %s\n", 113 fd, peercred, len + 1, errstr); 114 115 puts("+++ exited with 0 +++"); 116 return 0; 117 } 118