(root)/
strace-6.5/
tests-mx32/
so_peercred.c
       1  /*
       2   * Check decoding of SO_PEERCRED socket option.
       3   *
       4   * Copyright (c) 2017 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2017-2021 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  #include "pidns.h"
      13  
      14  #include <stddef.h>
      15  #include <stdio.h>
      16  #include <string.h>
      17  #include <sys/socket.h>
      18  #include <unistd.h>
      19  
      20  #include "print_fields.h"
      21  
      22  static const char *errstr;
      23  
      24  static int
      25  get_peercred(int fd, void *val, socklen_t *len)
      26  {
      27  	int rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, val, len);
      28  	errstr = sprintrc(rc);
      29  	return rc;
      30  }
      31  
      32  static const char *
      33  so_str(void)
      34  {
      35  	static char buf[256];
      36  
      37  	if (!buf[0]) {
      38  #if XLAT_RAW
      39  		snprintf(buf, sizeof(buf),
      40  			 "%#x, %#x", SOL_SOCKET, SO_PEERCRED);
      41  #elif XLAT_VERBOSE
      42  		snprintf(buf, sizeof(buf),
      43  			 "%#x /* SOL_SOCKET */, %#x /* SO_PEERCRED */",
      44  			 SOL_SOCKET, SO_PEERCRED);
      45  #else
      46  		snprintf(buf, sizeof(buf),
      47  			 "SOL_SOCKET, SO_PEERCRED");
      48  #endif
      49  	}
      50  
      51  	return buf;
      52  }
      53  
      54  int
      55  main(void)
      56  {
      57  	PIDNS_TEST_INIT;
      58  
      59  	TAIL_ALLOC_OBJECT_CONST_PTR(struct ucred, peercred);
      60  	TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
      61  
      62  	const unsigned int sizeof_pid = sizeof(peercred->pid);
      63  	struct ucred *const pid = tail_alloc(sizeof_pid);
      64  
      65  	const unsigned int sizeof_pid_truncated = sizeof_pid - 1;
      66  	struct ucred *const pid_truncated =
      67  		tail_alloc(sizeof_pid_truncated);
      68  
      69  	const unsigned int sizeof_uid = offsetofend(struct ucred, uid);
      70  	struct ucred *const uid = tail_alloc(sizeof_uid);
      71  
      72  	const unsigned int sizeof_uid_truncated = sizeof_uid - 1;
      73  	struct ucred *const uid_truncated =
      74  		tail_alloc(sizeof_uid_truncated);
      75  
      76  	const unsigned int sizeof_gid_truncated =
      77  		offsetofend(struct ucred, gid) - 1;
      78  	struct ucred *const gid_truncated =
      79  		tail_alloc(sizeof_gid_truncated);
      80  
      81  	const char *pid_str = pidns_pid2str(PT_TGID);
      82  
      83  	int sv[2];
      84  	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
      85                  perror_msg_and_skip("socketpair AF_UNIX SOCK_STREAM");
      86  
      87  	/* classic getsockopt */
      88  	*len = sizeof(*peercred);
      89  	get_peercred(sv[0], peercred, len);
      90  	pidns_print_leader();
      91  	printf("getsockopt(%d, %s", sv[0], so_str());
      92  	printf(", {");
      93  	PRINT_FIELD_D(*peercred, pid);
      94  	printf("%s", pid_str);
      95  	printf(", ");
      96  	PRINT_FIELD_ID(*peercred, uid);
      97  	printf(", ");
      98  	PRINT_FIELD_ID(*peercred, gid);
      99  	printf("}, [%d]) = %s\n", *len, errstr);
     100  
     101  	/* getsockopt with zero optlen */
     102  	*len = 0;
     103  	get_peercred(sv[0], peercred, len);
     104  	pidns_print_leader();
     105  	printf("getsockopt(%d, %s, %p, [0]) = %s\n",
     106  	       sv[0], so_str(), peercred, errstr);
     107  
     108  	/* getsockopt with optlen larger than necessary - shortened */
     109  	*len = sizeof(*peercred) + 1;
     110  	get_peercred(sv[0], peercred, len);
     111  	pidns_print_leader();
     112  	printf("getsockopt(%d, %s", sv[0], so_str());
     113  	printf(", {");
     114  	PRINT_FIELD_D(*peercred, pid);
     115  	printf("%s", pid_str);
     116  	printf(", ");
     117  	PRINT_FIELD_ID(*peercred, uid);
     118  	printf(", ");
     119  	PRINT_FIELD_ID(*peercred, gid);
     120  	printf("}, [%u => %d]) = %s\n",
     121  	       (unsigned int) sizeof(*peercred) + 1, *len, errstr);
     122  
     123  	/*
     124  	 * getsockopt with optlen less than offsetofend(struct ucred, pid):
     125  	 * the part of struct ucred.pid is printed in hex.
     126  	 */
     127  	*len = sizeof_pid_truncated;
     128  	get_peercred(sv[0], pid_truncated, len);
     129  	pidns_print_leader();
     130  	printf("getsockopt(%d, %s, {pid=", sv[0], so_str());
     131  	print_quoted_hex(pid_truncated, *len);
     132  	printf("}, [%d]) = %s\n", *len, errstr);
     133  
     134  	/*
     135  	 * getsockopt with optlen equals to sizeof(struct ucred.pid):
     136  	 * struct ucred.uid and struct ucred.gid are not printed.
     137  	 */
     138  	*len = sizeof_pid;
     139  	get_peercred(sv[0], pid, len);
     140  	pidns_print_leader();
     141  	printf("getsockopt(%d, %s", sv[0], so_str());
     142  	printf(", {");
     143  	PRINT_FIELD_D(*pid, pid);
     144  	printf("%s", pid_str);
     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  	pidns_print_leader();
     160  	printf("getsockopt(%d, %s", sv[0], so_str());
     161  	printf(", {");
     162  	PRINT_FIELD_D(*uid, pid);
     163  	printf("%s", pid_str);
     164  	printf(", uid=");
     165  	print_quoted_hex(&uid->uid, sizeof_uid_truncated -
     166  				    offsetof(struct ucred, uid));
     167  	printf("}, [%d]) = %s\n", *len, errstr);
     168  
     169  	/*
     170  	 * getsockopt with optlen equals to offsetofend(struct ucred, uid):
     171  	 * struct ucred.gid is not printed.
     172  	 */
     173  	*len = sizeof_uid;
     174  	get_peercred(sv[0], uid, len);
     175  	pidns_print_leader();
     176  	printf("getsockopt(%d, %s", sv[0], so_str());
     177  	printf(", {");
     178  	PRINT_FIELD_D(*uid, pid);
     179  	printf("%s", pid_str);
     180  	printf(", ");
     181  	PRINT_FIELD_ID(*uid, uid);
     182  	printf("}, [%d]) = %s\n", *len, errstr);
     183  
     184  	/*
     185  	 * getsockopt with optlen greater than sizeof(struct ucred.uid)
     186  	 * but smaller than offsetofend(struct ucred, gid):
     187  	 * the part of struct ucred.gid is printed in hex.
     188  	 */
     189  	*len = sizeof_gid_truncated;
     190  	get_peercred(sv[0], gid_truncated, len);
     191  	/*
     192  	 * Copy to a properly aligned structure to avoid unaligned access
     193  	 * to struct ucred.pid and struct ucred.uid fields.
     194  	 */
     195  	memcpy(peercred, gid_truncated, sizeof_gid_truncated);
     196  	pidns_print_leader();
     197  	printf("getsockopt(%d, %s", sv[0], so_str());
     198  	printf(", {");
     199  	PRINT_FIELD_D(*peercred, pid);
     200  	printf("%s", pid_str);
     201  	printf(", ");
     202  	PRINT_FIELD_ID(*peercred, uid);
     203  	printf(", gid=");
     204  	print_quoted_hex(&peercred->gid, sizeof_gid_truncated -
     205  				    offsetof(struct ucred, gid));
     206  	printf("}, [%d]) = %s\n", *len, errstr);
     207  
     208  	/* getsockopt optval EFAULT */
     209  	*len = sizeof(*peercred);
     210  	get_peercred(sv[0], &peercred->uid, len);
     211  	pidns_print_leader();
     212  	printf("getsockopt(%d, %s, %p, [%d]) = %s\n",
     213  	       sv[0], so_str(), &peercred->uid, *len, errstr);
     214  
     215  	/* getsockopt optlen EFAULT */
     216  	get_peercred(sv[0], peercred, len + 1);
     217  	pidns_print_leader();
     218  	printf("getsockopt(%d, %s, %p, %p) = %s\n",
     219  	       sv[0], so_str(), peercred, len + 1, errstr);
     220  
     221  	pidns_print_leader();
     222  	puts("+++ exited with 0 +++");
     223  	return 0;
     224  }