(root)/
strace-6.5/
tests/
ipc_shm.c
       1  /*
       2   * Copyright (c) 2015 Elvira Khabirova <lineprinter0@gmail.com>
       3   * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
       4   * Copyright (c) 2015-2020 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  #include <errno.h>
      12  #include <stdio.h>
      13  #include <stdlib.h>
      14  #include <sys/shm.h>
      15  
      16  #ifndef SHM_HUGE_SHIFT
      17  # define SHM_HUGE_SHIFT 26
      18  #endif
      19  
      20  #ifndef SHM_HUGE_MASK
      21  # define SHM_HUGE_MASK 0x3f
      22  #endif
      23  
      24  #ifndef SHM_STAT_ANY
      25  # define SHM_STAT_ANY 15
      26  #endif
      27  
      28  #ifndef SHM_NORESERVE
      29  # define SHM_NORESERVE 010000
      30  #endif
      31  
      32  #undef TEST_SHMCTL_BOGUS_ADDR
      33  #undef TEST_SHMCTL_BOGUS_CMD
      34  
      35  /*
      36   * Starting with commit glibc-2.32~80, on every 32-bit architecture
      37   * where 32-bit time_t support is enabled, glibc tries to retrieve
      38   * the data provided in the third argument of shmctl call.
      39   */
      40  #if GLIBC_PREREQ_GE(2, 32) && defined __TIMESIZE && __TIMESIZE != 64
      41  # define TEST_SHMCTL_BOGUS_ADDR 0
      42  #endif
      43  
      44  /*
      45   * Starting with commit glibc-2.32.9000-207-g9ebaabeaac1a96b0d91f,
      46   * glibc skips shmctl syscall invocations and returns EINVAL
      47   * for invalid shmctl commands.
      48   */
      49  #if GLIBC_PREREQ_GE(2, 32)
      50  # define TEST_SHMCTL_BOGUS_CMD 0
      51  #endif
      52  
      53  #ifndef TEST_SHMCTL_BOGUS_ADDR
      54  # define TEST_SHMCTL_BOGUS_ADDR 1
      55  #endif
      56  #ifndef TEST_SHMCTL_BOGUS_CMD
      57  # define TEST_SHMCTL_BOGUS_CMD 1
      58  #endif
      59  
      60  #include "xlat.h"
      61  #include "xlat/shm_resource_flags.h"
      62  
      63  #if XLAT_RAW
      64  # define str_ipc_flags "0x2ce1e00"
      65  # define str_shm_huge "21<<26"
      66  # define str_ipc_private "0"
      67  # define str_ipc_rmid "0"
      68  # define str_ipc_set "0x1"
      69  # define str_ipc_stat "0x2"
      70  # define str_ipc_info "0x3"
      71  # define str_shm_stat "0xd"
      72  # define str_shm_info "0xe"
      73  # define str_shm_stat_any "0xf"
      74  # define str_ipc_64 "0x100"
      75  # define str_bogus_cmd "0xdefaced2"
      76  #elif XLAT_VERBOSE
      77  # define str_ipc_flags \
      78  	"0x2ce1e00 /\\* IPC_CREAT\\|IPC_EXCL\\|SHM_HUGETLB\\|SHM_NORESERVE" \
      79  	"\\|0x2ce0000 \\*/"
      80  # define str_shm_huge "21<<26 /\\* SHM_HUGE_SHIFT \\*/"
      81  # define str_ipc_private "0 /\\* IPC_PRIVATE \\*/"
      82  # define str_ipc_rmid "0 /\\* IPC_RMID \\*/"
      83  # define str_ipc_set "0x1 /\\* IPC_SET \\*/"
      84  # define str_ipc_stat "0x2 /\\* IPC_STAT \\*/"
      85  # define str_ipc_info "0x3 /\\* IPC_INFO \\*/"
      86  # define str_shm_stat "0xd /\\* SHM_STAT \\*/"
      87  # define str_shm_info "0xe /\\* SHM_INFO \\*/"
      88  # define str_shm_stat_any "0xf /\\* SHM_STAT_ANY \\*/"
      89  # define str_ipc_64 "0x100 /\\* IPC_64 \\*/"
      90  # define str_bogus_cmd "0xdefaced2 /\\* SHM_\\?\\?\\? \\*/"
      91  #else
      92  # define str_ipc_flags \
      93  	"IPC_CREAT\\|IPC_EXCL\\|SHM_HUGETLB\\|SHM_NORESERVE\\|0x2ce0000"
      94  # define str_shm_huge "21<<SHM_HUGE_SHIFT"
      95  # define str_ipc_private "IPC_PRIVATE"
      96  # define str_ipc_rmid "IPC_RMID"
      97  # define str_ipc_set "IPC_SET"
      98  # define str_ipc_stat "IPC_STAT"
      99  # define str_ipc_info "IPC_INFO"
     100  # define str_shm_stat "SHM_STAT"
     101  # define str_shm_info "SHM_INFO"
     102  # define str_shm_stat_any "SHM_STAT_ANY"
     103  # define str_ipc_64 "IPC_64"
     104  # define str_bogus_cmd "0xdefaced2 /\\* SHM_\\?\\?\\? \\*/"
     105  #endif
     106  
     107  static int id = -1;
     108  
     109  static void
     110  cleanup(void)
     111  {
     112  	shmctl(id, IPC_RMID, NULL);
     113  	printf("shmctl\\(%d, (%s\\|)?%s, NULL\\) = 0\n",
     114  	       id, str_ipc_64, str_ipc_rmid);
     115  	id = -1;
     116  }
     117  
     118  static void
     119  print_shmid_ds(const char *const str_ipc_cmd,
     120  	       const struct shmid_ds *const ds,
     121  	       const int rc)
     122  {
     123  	if (rc < 0) {
     124  		printf("shmctl\\(%d, (%s\\|)?%s, %p\\) = %s\n",
     125  		       id, str_ipc_64, str_ipc_cmd, ds, sprintrc_grep(rc));
     126  		return;
     127  	}
     128  	printf("shmctl\\(%d, (%s\\|)?%s, \\{shm_perm=\\{uid=%u, gid=%u"
     129  		", mode=%#o, key=%u, cuid=%u, cgid=%u\\}, shm_segsz=%u"
     130  		", shm_cpid=%d, shm_lpid=%d, shm_nattch=%u, shm_atime=%u"
     131  		", shm_dtime=%u, shm_ctime=%u\\}\\) = %d\n",
     132  		id,
     133  		str_ipc_64,
     134  		str_ipc_cmd,
     135  		(unsigned) ds->shm_perm.uid,
     136  		(unsigned) ds->shm_perm.gid,
     137  		(unsigned) ds->shm_perm.mode,
     138  		(unsigned) ds->shm_perm.__key,
     139  		(unsigned) ds->shm_perm.cuid,
     140  		(unsigned) ds->shm_perm.cgid,
     141  		(unsigned) ds->shm_segsz,
     142  		(int) ds->shm_cpid,
     143  		(int) ds->shm_lpid,
     144  		(unsigned) ds->shm_nattch,
     145  		(unsigned) ds->shm_atime,
     146  		(unsigned) ds->shm_dtime,
     147  		(unsigned) ds->shm_ctime,
     148  		rc);
     149  }
     150  
     151  static void
     152  print_ipc_info(const char *const str_ipc_cmd,
     153                 const struct shminfo *const info,
     154                 const int rc)
     155  {
     156  	if (rc < 0) {
     157  		printf("shmctl\\(%d, (%s\\|)?%s, %p\\) = %s\n",
     158  		       id, str_ipc_64, str_ipc_cmd, info, sprintrc_grep(rc));
     159  		return;
     160  	}
     161  
     162  	printf("shmctl\\(%d, (%s\\|)?%s, \\{shmmax=%llu, shmmin=%llu"
     163  	       ", shmmni=%llu, shmseg=%llu, shmall=%llu\\}\\) = %d\n",
     164  	       id,
     165  	       str_ipc_64,
     166  	       str_ipc_cmd,
     167  	       (unsigned long long) info->shmmax,
     168  	       (unsigned long long) info->shmmin,
     169  	       (unsigned long long) info->shmmni,
     170  	       (unsigned long long) info->shmseg,
     171  	       (unsigned long long) info->shmall,
     172  	       rc);
     173  }
     174  
     175  static void
     176  print_shm_info(const char *const str_ipc_cmd,
     177                const struct shm_info *const info,
     178                const int rc)
     179  {
     180  	if (rc < 0) {
     181  		printf("shmctl\\(%d, (%s\\|)?%s, %p\\) = %s\n",
     182  		       id, str_ipc_64, str_ipc_cmd, info, sprintrc_grep(rc));
     183  		return;
     184  	}
     185  
     186  	printf("shmctl\\(%d, (%s\\|)?%s, \\{used_ids=%d, shm_tot=%llu"
     187  	       ", shm_rss=%llu, shm_swp=%llu, swap_attempts=%llu"
     188  	       ", swap_successes=%llu\\}\\) = %d\n",
     189  	       id,
     190  	       str_ipc_64,
     191  	       str_ipc_cmd,
     192  	       info->used_ids,
     193  	       (unsigned long long) info->shm_tot,
     194  	       (unsigned long long) info->shm_rss,
     195  	       (unsigned long long) info->shm_swp,
     196  	       (unsigned long long) info->swap_attempts,
     197  	       (unsigned long long) info->swap_successes,
     198  	       rc);
     199  }
     200  
     201  int
     202  main(void)
     203  {
     204  	static const key_t private_key =
     205  		(key_t) (0xffffffff00000000ULL | IPC_PRIVATE);
     206  	static const key_t bogus_key = (key_t) 0xeca86420fdb97531ULL;
     207  #if TEST_SHMCTL_BOGUS_CMD || TEST_SHMCTL_BOGUS_ADDR
     208  	static const int bogus_id = 0xdefaced1;
     209  #endif
     210  #if TEST_SHMCTL_BOGUS_CMD
     211  	static const int bogus_cmd = 0xdefaced2;
     212  #endif
     213  #if TEST_SHMCTL_BOGUS_ADDR
     214  	static void * const bogus_addr = (void *) -1L;
     215  #endif
     216  	static const size_t bogus_size =
     217  	/*
     218  	 * musl sets size to SIZE_MAX if size argument is greater than
     219  	 * PTRDIFF_MAX - musl/src/ipc/shmget.c
     220  	 */
     221  #ifdef __GLIBC__
     222  		(size_t) 0xdec0ded1dec0ded2ULL;
     223  #else
     224  		(size_t) 0x1e55c0de5dec0dedULL;
     225  #endif
     226  	static const unsigned int bogus_ipc_shm_flags =
     227  		IPC_CREAT | IPC_EXCL | SHM_HUGETLB | SHM_NORESERVE;
     228  	static const unsigned int huge_mask = SHM_HUGE_MASK << SHM_HUGE_SHIFT;
     229  	static const unsigned int huge_flags = 21 << SHM_HUGE_SHIFT;
     230  	int bogus_flags;
     231  	int rc;
     232  	union {
     233  		struct shmid_ds ds;
     234  		struct shminfo ipc_info;
     235  		struct shm_info shm_info;
     236  	} buf;
     237  
     238  	rc = shmget(bogus_key, bogus_size, 0);
     239  	printf("shmget\\(%#llx, %zu, 000\\) = %s\n",
     240  	       zero_extend_signed_to_ull(bogus_key), bogus_size,
     241  	       sprintrc_grep(rc));
     242  
     243  	rc = shmget(bogus_key, bogus_size, huge_flags);
     244  	printf("shmget\\(%#llx, %zu, %s\\|%#03o\\) = %s\n",
     245  	       zero_extend_signed_to_ull(bogus_key), bogus_size,
     246  	       str_shm_huge, 0, sprintrc_grep(rc));
     247  
     248  	bogus_flags = 0xface1e55 & ~(bogus_ipc_shm_flags | huge_mask);
     249  	rc = shmget(bogus_key, bogus_size, bogus_flags);
     250  	printf("shmget\\(%#llx, %zu, %#x\\|%#03o\\) = %s\n",
     251  	       zero_extend_signed_to_ull(bogus_key), bogus_size,
     252  	       bogus_flags & ~0777,
     253  	       bogus_flags & 0777, sprintrc_grep(rc));
     254  
     255  	bogus_flags |= bogus_ipc_shm_flags;
     256  	rc = shmget(bogus_key, bogus_size, bogus_flags);
     257  	printf("shmget\\(%#llx, %zu, %s\\|%#03o\\) = %s\n",
     258  	       zero_extend_signed_to_ull(bogus_key), bogus_size,
     259  	       str_ipc_flags,
     260  	       bogus_flags & 0777, sprintrc_grep(rc));
     261  
     262  	bogus_flags |= huge_flags;
     263  	rc = shmget(bogus_key, bogus_size, bogus_flags);
     264  	printf("shmget\\(%#llx, %zu, %s\\|%s\\|%#03o\\) = %s\n",
     265  	       zero_extend_signed_to_ull(bogus_key), bogus_size,
     266  	       str_ipc_flags, str_shm_huge,
     267  	       bogus_flags & 0777, sprintrc_grep(rc));
     268  
     269  	bogus_flags &= ~bogus_ipc_shm_flags;
     270  	rc = shmget(bogus_key, bogus_size, bogus_flags);
     271  	printf("shmget\\(%#llx, %zu, %#x\\|%s\\|%#03o\\) = %s\n",
     272  	       zero_extend_signed_to_ull(bogus_key), bogus_size,
     273  	       bogus_flags & ~(0777 | huge_mask),
     274  	       str_shm_huge,
     275  	       bogus_flags & 0777, sprintrc_grep(rc));
     276  
     277  	id = shmget(private_key, 1, 0600);
     278  	if (id < 0)
     279  		perror_msg_and_skip("shmget");
     280  	printf("shmget\\(%s, 1, 0600\\) = %d\n", str_ipc_private, id);
     281  	atexit(cleanup);
     282  
     283  #if TEST_SHMCTL_BOGUS_CMD
     284  	rc = shmctl(bogus_id, bogus_cmd, NULL);
     285  	printf("shmctl\\(%d, (%s\\|)?%s, NULL\\) = %s\n",
     286  	       bogus_id, str_ipc_64, str_bogus_cmd, sprintrc_grep(rc));
     287  #endif
     288  
     289  #if TEST_SHMCTL_BOGUS_ADDR
     290  	rc = shmctl(bogus_id, IPC_STAT, bogus_addr);
     291  	printf("shmctl\\(%d, (%s\\|)?%s, %p\\) = %s\n",
     292  	       bogus_id, str_ipc_64, str_ipc_stat, bogus_addr,
     293  	       sprintrc_grep(rc));
     294  #endif
     295  
     296  	rc = shmctl(id, IPC_STAT, &buf.ds);
     297  	if (rc < 0)
     298  		perror_msg_and_skip("shmctl IPC_STAT");
     299  	print_shmid_ds(str_ipc_stat, &buf.ds, rc);
     300  
     301  	if (shmctl(id, IPC_SET, &buf.ds))
     302  		perror_msg_and_skip("shmctl IPC_SET");
     303  	printf("shmctl\\(%d, (%s\\|)?%s, \\{shm_perm=\\{uid=%u, gid=%u"
     304  	       ", mode=%#o\\}\\}\\) = 0\n",
     305  	       id, str_ipc_64, str_ipc_set,
     306  	       (unsigned) buf.ds.shm_perm.uid,
     307  	       (unsigned) buf.ds.shm_perm.gid,
     308  	       (unsigned) buf.ds.shm_perm.mode);
     309  
     310  	rc = shmctl(id, IPC_INFO, &buf.ds);
     311  	print_ipc_info(str_ipc_info, &buf.ipc_info, rc);
     312  
     313  	rc = shmctl(id, SHM_INFO, &buf.ds);
     314  	print_shm_info(str_shm_info, &buf.shm_info, rc);
     315  
     316  	rc = shmctl(id, SHM_STAT, &buf.ds);
     317  	print_shmid_ds(str_shm_stat, &buf.ds, rc);
     318  
     319  	rc = shmctl(id, SHM_STAT_ANY, &buf.ds);
     320  	print_shmid_ds(str_shm_stat_any, &buf.ds, rc);
     321  
     322  	return 0;
     323  }