1 /* 2 * Check decoding of SO_PEERCRED socket option. 3 * 4 * Copyright (c) 2017 Dmitry V. Levin <ldv (at) altlinux.org> 5 * Copyright (c) 2017-2018 The strace developers. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "tests.h" 32 33 #include <stddef.h> 34 #include <stdio.h> 35 #include <string.h> 36 #include <sys/socket.h> 37 #include <unistd.h> 38 39 #include "print_fields.h" 40 41 static const char *errstr; 42 43 static int 44 get_peercred(int fd, void *val, socklen_t *len) 45 { 46 int rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, val, len); 47 errstr = sprintrc(rc); 48 return rc; 49 } 50 51 static const char * 52 so_str(void) 53 { 54 static char buf[256]; 55 56 if (!buf[0]) { 57 #if XLAT_RAW 58 snprintf(buf, sizeof(buf), 59 "%#x, %#x", SOL_SOCKET, SO_PEERCRED); 60 #elif XLAT_VERBOSE 61 snprintf(buf, sizeof(buf), 62 "%#x /* SOL_SOCKET */, %#x /* SO_PEERCRED */", 63 SOL_SOCKET, SO_PEERCRED); 64 #else 65 snprintf(buf, sizeof(buf), 66 "SOL_SOCKET, SO_PEERCRED"); 67 #endif 68 } 69 70 return buf; 71 } 72 73 int 74 main(void) 75 { 76 TAIL_ALLOC_OBJECT_CONST_PTR(struct ucred, peercred); 77 TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len); 78 79 const unsigned int sizeof_pid = sizeof(peercred->pid); 80 struct ucred *const pid = tail_alloc(sizeof_pid); 81 82 const unsigned int sizeof_pid_truncated = sizeof_pid - 1; 83 struct ucred *const pid_truncated = 84 tail_alloc(sizeof_pid_truncated); 85 86 const unsigned int sizeof_uid = offsetofend(struct ucred, uid); 87 struct ucred *const uid = tail_alloc(sizeof_uid); 88 89 const unsigned int sizeof_uid_truncated = sizeof_uid - 1; 90 struct ucred *const uid_truncated = 91 tail_alloc(sizeof_uid_truncated); 92 93 const unsigned int sizeof_gid_truncated = 94 offsetofend(struct ucred, gid) - 1; 95 struct ucred *const gid_truncated = 96 tail_alloc(sizeof_gid_truncated); 97 98 int sv[2]; 99 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) 100 perror_msg_and_skip("socketpair AF_UNIX SOCK_STREAM"); 101 102 /* classic getsockopt */ 103 *len = sizeof(*peercred); 104 get_peercred(sv[0], peercred, len); 105 printf("getsockopt(%d, %s", sv[0], so_str()); 106 PRINT_FIELD_D(", {", *peercred, pid); 107 PRINT_FIELD_UID(", ", *peercred, uid); 108 PRINT_FIELD_UID(", ", *peercred, gid); 109 printf("}, [%d]) = %s\n", *len, errstr); 110 111 /* getsockopt with zero optlen */ 112 *len = 0; 113 get_peercred(sv[0], peercred, len); 114 printf("getsockopt(%d, %s, %p, [0]) = %s\n", 115 sv[0], so_str(), peercred, errstr); 116 117 /* getsockopt with optlen larger than necessary - shortened */ 118 *len = sizeof(*peercred) + 1; 119 get_peercred(sv[0], peercred, len); 120 printf("getsockopt(%d, %s", sv[0], so_str()); 121 PRINT_FIELD_D(", {", *peercred, pid); 122 PRINT_FIELD_UID(", ", *peercred, uid); 123 PRINT_FIELD_UID(", ", *peercred, gid); 124 printf("}, [%u->%d]) = %s\n", 125 (unsigned int) sizeof(*peercred) + 1, *len, errstr); 126 127 /* 128 * getsockopt with optlen less than offsetofend(struct ucred, pid): 129 * the part of struct ucred.pid is printed in hex. 130 */ 131 *len = sizeof_pid_truncated; 132 get_peercred(sv[0], pid_truncated, len); 133 printf("getsockopt(%d, %s, {pid=", sv[0], so_str()); 134 print_quoted_hex(pid_truncated, *len); 135 printf("}, [%d]) = %s\n", *len, errstr); 136 137 /* 138 * getsockopt with optlen equals to sizeof(struct ucred.pid): 139 * struct ucred.uid and struct ucred.gid are not printed. 140 */ 141 *len = sizeof_pid; 142 get_peercred(sv[0], pid, len); 143 printf("getsockopt(%d, %s", sv[0], so_str()); 144 PRINT_FIELD_D(", {", *pid, pid); 145 printf("}, [%d]) = %s\n", *len, errstr); 146 147 /* 148 * getsockopt with optlen greater than sizeof(struct ucred.pid) 149 * but smaller than offsetofend(struct ucred, uid): 150 * the part of struct ucred.uid is printed in hex. 151 */ 152 *len = sizeof_uid_truncated; 153 get_peercred(sv[0], uid_truncated, len); 154 /* 155 * Copy to a properly aligned structure to avoid unaligned access 156 * to struct ucred.pid field. 157 */ 158 memcpy(uid, uid_truncated, sizeof_uid_truncated); 159 printf("getsockopt(%d, %s", sv[0], so_str()); 160 PRINT_FIELD_D(", {", *uid, pid); 161 printf(", uid="); 162 print_quoted_hex(&uid->uid, sizeof_uid_truncated - 163 offsetof(struct ucred, uid)); 164 printf("}, [%d]) = %s\n", *len, errstr); 165 166 /* 167 * getsockopt with optlen equals to offsetofend(struct ucred, uid): 168 * struct ucred.gid is not printed. 169 */ 170 *len = sizeof_uid; 171 get_peercred(sv[0], uid, len); 172 printf("getsockopt(%d, %s", sv[0], so_str()); 173 PRINT_FIELD_D(", {", *uid, pid); 174 PRINT_FIELD_UID(", ", *uid, uid); 175 printf("}, [%d]) = %s\n", *len, errstr); 176 177 /* 178 * getsockopt with optlen greater than sizeof(struct ucred.uid) 179 * but smaller than offsetofend(struct ucred, gid): 180 * the part of struct ucred.gid is printed in hex. 181 */ 182 *len = sizeof_gid_truncated; 183 get_peercred(sv[0], gid_truncated, len); 184 /* 185 * Copy to a properly aligned structure to avoid unaligned access 186 * to struct ucred.pid and struct ucred.uid fields. 187 */ 188 memcpy(peercred, gid_truncated, sizeof_gid_truncated); 189 printf("getsockopt(%d, %s", sv[0], so_str()); 190 PRINT_FIELD_D(", {", *peercred, pid); 191 PRINT_FIELD_UID(", ", *peercred, uid); 192 printf(", gid="); 193 print_quoted_hex(&peercred->gid, sizeof_gid_truncated - 194 offsetof(struct ucred, gid)); 195 printf("}, [%d]) = %s\n", *len, errstr); 196 197 /* getsockopt optval EFAULT */ 198 *len = sizeof(*peercred); 199 get_peercred(sv[0], &peercred->uid, len); 200 printf("getsockopt(%d, %s, %p, [%d]) = %s\n", 201 sv[0], so_str(), &peercred->uid, *len, errstr); 202 203 /* getsockopt optlen EFAULT */ 204 get_peercred(sv[0], peercred, len + 1); 205 printf("getsockopt(%d, %s, %p, %p) = %s\n", 206 sv[0], so_str(), peercred, len + 1, errstr); 207 208 puts("+++ exited with 0 +++"); 209 return 0; 210 } 211