(root)/
strace-6.5/
tests-m32/
ioctl_ubi.c
       1  /*
       2   * Check decoding of UBI ioctl commands.
       3   *
       4   * Copyright (c) 2016-2021 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  
      12  #include <stdio.h>
      13  #include <stdlib.h>
      14  #include <string.h>
      15  #include <sys/ioctl.h>
      16  #include <mtd/ubi-user.h>
      17  
      18  static const unsigned long long llmagic = 0xdeadbeefbadc0dedULL;
      19  static const unsigned long lmagic = (unsigned long) 0xdeadbeefbadc0dedULL;
      20  static const unsigned int imagic = 0xdeadbeef;
      21  
      22  static const char *errstr;
      23  
      24  static int
      25  do_ioctl(kernel_ulong_t cmd, kernel_ulong_t arg)
      26  {
      27  	int rc = ioctl(-1, cmd, arg);
      28  	errstr = sprintrc(rc);
      29  
      30  #ifdef INJECT_RETVAL
      31  	if (rc != INJECT_RETVAL)
      32  		error_msg_and_fail("Return value [%d] does not match"
      33  				   " expectations [%d]", rc, INJECT_RETVAL);
      34  
      35  	static char inj_errstr[4096];
      36  
      37  	snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
      38  	errstr = inj_errstr;
      39  #endif
      40  
      41  	return rc;
      42  }
      43  
      44  static int
      45  do_ioctl_ptr(kernel_ulong_t cmd, const void *arg)
      46  {
      47  	return do_ioctl(cmd, (uintptr_t) arg);
      48  }
      49  
      50  #ifdef INJECT_RETVAL
      51  static void
      52  skip_ioctls(int argc, const char *argv[])
      53  {
      54  	if (argc < 2)
      55  		error_msg_and_fail("Usage: %s NUM_SKIP", argv[0]);
      56  
      57  	unsigned long num_skip = strtoul(argv[1], NULL, 0);
      58  
      59  	for (size_t i = 0; i < num_skip; ++i) {
      60  		int rc = ioctl(-1, UBI_IOCATT, 0);
      61  		printf("ioctl(-1, UBI_IOCATT, NULL) = %s%s\n", sprintrc(rc),
      62  		       rc == INJECT_RETVAL ? " (INJECTED)" : "");
      63  		if (rc == INJECT_RETVAL)
      64  			return;
      65  	}
      66  
      67  	error_msg_and_fail("Issued %lu ioctl syscalls but failed"
      68  			   " to detect an injected return code %d",
      69  			   num_skip, INJECT_RETVAL);
      70  }
      71  #endif /* INJECT_RETVAL */
      72  
      73  int
      74  main(int argc, const char *argv[])
      75  {
      76  #ifdef INJECT_RETVAL
      77  	skip_ioctls(argc, argv);
      78  #endif
      79  
      80  	static const struct {
      81  		unsigned int cmd;
      82  		const char *str;
      83  	}
      84  	noarg_cmds[] = {
      85  		{ ARG_STR(UBI_IOCVOLCRBLK) },
      86  		{ ARG_STR(UBI_IOCVOLRMBLK) },
      87  	},
      88  	pint_cmds[] = {
      89  		{ ARG_STR(UBI_IOCDET) },
      90  		{ ARG_STR(UBI_IOCEBER) },
      91  		{ ARG_STR(UBI_IOCEBISMAP) },
      92  		{ ARG_STR(UBI_IOCEBUNMAP) },
      93  		{ ARG_STR(UBI_IOCRMVOL) },
      94  		{ ARG_STR(UBI_IOCRPEB) },
      95  		{ ARG_STR(UBI_IOCSPEB) },
      96  	}, pint64_cmds[] = {
      97  		{ ARG_STR(UBI_IOCVOLUP) },
      98  	}, ptr_cmds[] = {
      99  		{ ARG_STR(UBI_IOCATT) },
     100  		{ ARG_STR(UBI_IOCEBCH) },
     101  		{ ARG_STR(UBI_IOCEBMAP) },
     102  		{ ARG_STR(UBI_IOCMKVOL) },
     103  		{ ARG_STR(UBI_IOCRNVOL) },
     104  		{ ARG_STR(UBI_IOCRSVOL) },
     105  		{ ARG_STR(UBI_IOCSETVOLPROP) },
     106  	}, attach_cmds[] = {
     107  		{ ARG_STR(UBI_IOCATT) },
     108  	}, leb_cmds[] = {
     109  		{ ARG_STR(UBI_IOCEBCH) },
     110  	}, map_cmds[] = {
     111  		{ ARG_STR(UBI_IOCEBMAP) },
     112  	}, mkvol_cmds[] = {
     113  		{ ARG_STR(UBI_IOCMKVOL) },
     114  	}, rnvol_cmds[] = {
     115  		{ ARG_STR(UBI_IOCRNVOL) },
     116  	}, rsvol_cmds[] = {
     117  		{ ARG_STR(UBI_IOCRSVOL) },
     118  	}, prop_cmds[] = {
     119  		{ ARG_STR(UBI_IOCSETVOLPROP) },
     120  	};
     121  
     122  	for (size_t i = 0; i < ARRAY_SIZE(noarg_cmds); ++i) {
     123  		do_ioctl(noarg_cmds[i].cmd, lmagic);
     124  		printf("ioctl(-1, %s) = %s\n",
     125  		       noarg_cmds[i].str, errstr);
     126  	}
     127  
     128  	TAIL_ALLOC_OBJECT_CONST_PTR(int, pint);
     129  	*pint = imagic;
     130  
     131  	for (size_t i = 0; i < ARRAY_SIZE(pint_cmds); ++i) {
     132  		do_ioctl_ptr(pint_cmds[i].cmd, pint);
     133  		printf("ioctl(-1, %s, [%d]) = %s\n",
     134  		       pint_cmds[i].str, *pint, errstr);
     135  	}
     136  
     137  	TAIL_ALLOC_OBJECT_CONST_PTR(int64_t, pint64);
     138  	*pint64 = (int64_t) llmagic;
     139  
     140  	for (size_t i = 0; i < ARRAY_SIZE(pint64_cmds); ++i) {
     141  		do_ioctl_ptr(pint64_cmds[i].cmd, pint64);
     142  		printf("ioctl(-1, %s, [%jd]) = %s\n",
     143  		       pint64_cmds[i].str, (intmax_t) *pint64, errstr);
     144  	}
     145  
     146  	void *const efault = tail_alloc(1);
     147  
     148  	for (size_t i = 0; i < ARRAY_SIZE(ptr_cmds); ++i) {
     149  		do_ioctl(ptr_cmds[i].cmd, 0);
     150  		printf("ioctl(-1, %s, NULL) = %s\n",
     151  		       ptr_cmds[i].str, errstr);
     152  		do_ioctl_ptr(ptr_cmds[i].cmd, efault);
     153  		printf("ioctl(-1, %s, %p) = %s\n",
     154  		       ptr_cmds[i].str, efault, errstr);
     155  	}
     156  
     157  	TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_attach_req, attach);
     158  	fill_memory(attach, sizeof(*attach));
     159  
     160  	for (size_t i = 0; i < ARRAY_SIZE(attach_cmds); ++i) {
     161  		int rc = do_ioctl_ptr(attach_cmds[i].cmd, attach);
     162  		printf("ioctl(-1, %s, {ubi_num=%d, mtd_num=%d"
     163  		       ", vid_hdr_offset=%d, max_beb_per1024=%hd}",
     164  		       attach_cmds[i].str, attach->ubi_num,
     165  		       attach->mtd_num, attach->vid_hdr_offset,
     166  		       attach->max_beb_per1024);
     167  		if (rc >= 0)
     168  			printf(" => [%d]", attach->ubi_num);
     169  		printf(") = %s\n", errstr);
     170  	}
     171  
     172  	TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_leb_change_req, leb);
     173  	fill_memory(leb, sizeof(*leb));
     174  	leb->dtype = 3;
     175  
     176  	for (size_t i = 0; i < ARRAY_SIZE(leb_cmds); ++i) {
     177  		do_ioctl_ptr(leb_cmds[i].cmd, leb);
     178  		printf("ioctl(-1, %s, {lnum=%d, bytes=%d, dtype=%s}) = %s\n",
     179  		       leb_cmds[i].str, leb->lnum, leb->bytes, "UBI_UNKNOWN",
     180  		       errstr);
     181  	}
     182  
     183  	TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_map_req, map);
     184  	fill_memory(map, sizeof(*map));
     185  	map->dtype = 3;
     186  
     187  	for (size_t i = 0; i < ARRAY_SIZE(map_cmds); ++i) {
     188  		do_ioctl_ptr(map_cmds[i].cmd, map);
     189  		printf("ioctl(-1, %s, {lnum=%d, dtype=%s}) = %s\n",
     190  		       map_cmds[i].str, map->lnum, "UBI_UNKNOWN", errstr);
     191  	}
     192  
     193  	TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_mkvol_req, mkvol);
     194  	fill_memory(mkvol, sizeof(*mkvol));
     195  	mkvol->vol_type = 4;
     196  	mkvol->flags = 1;
     197  	fill_memory_ex(mkvol->name, sizeof(mkvol->name), '0', 10);
     198  
     199  	for (size_t i = 0; i < ARRAY_SIZE(mkvol_cmds); ++i) {
     200  		static const int lens[] = {
     201  			-1, 0, 1, UBI_MAX_VOLUME_NAME,
     202  			UBI_MAX_VOLUME_NAME + 1
     203  		};
     204  		for (size_t j = 0; j < ARRAY_SIZE(lens); ++j) {
     205  			mkvol->name_len = lens[j];
     206  			int len = CLAMP(mkvol->name_len, 0,
     207  					UBI_MAX_VOLUME_NAME);
     208  			int rc = do_ioctl_ptr(mkvol_cmds[i].cmd, mkvol);
     209  			printf("ioctl(-1, %s, {vol_id=%d, alignment=%d"
     210  			       ", bytes=%jd, vol_type=%s, flags=%s"
     211  			       ", name_len=%hd, name=\"%.*s\"...}",
     212  			       mkvol_cmds[i].str, mkvol->vol_id,
     213  			       mkvol->alignment, (intmax_t) mkvol->bytes,
     214  			       "UBI_STATIC_VOLUME",
     215  			       "UBI_VOL_SKIP_CRC_CHECK_FLG",
     216  			       mkvol->name_len, len, mkvol->name);
     217  			if (rc >= 0)
     218  				printf(" => [%d]", mkvol->vol_id);
     219  			printf(") = %s\n", errstr);
     220  		}
     221  	}
     222  
     223  	TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_rnvol_req, rnvol);
     224  
     225  	for (size_t i = 0; i < ARRAY_SIZE(rnvol_cmds); ++i) {
     226  		fill_memory(rnvol, sizeof(*rnvol));
     227  		do_ioctl_ptr(rnvol_cmds[i].cmd, rnvol);
     228  		printf("ioctl(-1, %s, {count=%d, ents=[]}) = %s\n",
     229  		       rnvol_cmds[i].str, rnvol->count, errstr);
     230  
     231  		rnvol->count = 1;
     232  		do_ioctl_ptr(rnvol_cmds[i].cmd, rnvol);
     233  		printf("ioctl(-1, %s, {count=%d, ents=[{vol_id=%d"
     234  		       ", name_len=%hd, name=\"\"...}]}) = %s\n",
     235  		       rnvol_cmds[i].str, rnvol->count,
     236  		       rnvol->ents[0].vol_id, rnvol->ents[0].name_len, errstr);
     237  
     238  		rnvol->count = UBI_MAX_RNVOL + 1;
     239  		for (size_t j = 0; j < UBI_MAX_RNVOL; ++j) {
     240  			fill_memory_ex(rnvol->ents[j].name,
     241  				       sizeof(rnvol->ents[j].name), '0', 10);
     242  		}
     243  		rnvol->ents[0].name_len = 0;
     244  		rnvol->ents[1].name_len = 1;
     245  		rnvol->ents[2].name_len = 1;
     246  		rnvol->ents[2].name[1] = '\0';
     247  		rnvol->ents[3].name_len = 2;
     248  		rnvol->ents[3].name[1] = '\0';
     249  		rnvol->ents[4].name_len = UBI_MAX_VOLUME_NAME;
     250  		rnvol->ents[5].name_len = UBI_MAX_VOLUME_NAME;
     251  		rnvol->ents[5].name[UBI_MAX_VOLUME_NAME] = '\0';
     252  		rnvol->ents[6].name_len = UBI_MAX_VOLUME_NAME;
     253  		rnvol->ents[6].name[UBI_MAX_VOLUME_NAME - 1] = '\0';
     254  		rnvol->ents[7].name_len = UBI_MAX_VOLUME_NAME + 1;
     255  		rnvol->ents[8].name_len = UBI_MAX_VOLUME_NAME + 1;
     256  		rnvol->ents[8].name[UBI_MAX_VOLUME_NAME] = '\0';
     257  		do_ioctl_ptr(rnvol_cmds[i].cmd, rnvol);
     258  		printf("ioctl(-1, %s, {count=%d, ents=[",
     259  		       rnvol_cmds[i].str, rnvol->count);
     260  		for (size_t j = 0; j < UBI_MAX_RNVOL; ++j) {
     261  			int len = CLAMP(rnvol->ents[j].name_len, 0,
     262  					UBI_MAX_VOLUME_NAME);
     263  			bool dots = rnvol->ents[j].name[len] &&
     264  				    (len <= 0 || rnvol->ents[j].name[len - 1]);
     265  			printf("%s{vol_id=%d, name_len=%hd, name=\"%.*s\"%s}",
     266  			       j ? ", " : "",
     267  			       rnvol->ents[j].vol_id,
     268  			       rnvol->ents[j].name_len,
     269  			       len, rnvol->ents[j].name,
     270  			       dots ? "..." : "");
     271  		}
     272  		printf("]}) = %s\n", errstr);
     273  	}
     274  
     275  	TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_rsvol_req, rsvol);
     276  	fill_memory(rsvol, sizeof(*rsvol));
     277  
     278  	for (size_t i = 0; i < ARRAY_SIZE(rsvol_cmds); ++i) {
     279  		do_ioctl_ptr(rsvol_cmds[i].cmd, rsvol);
     280  		printf("ioctl(-1, %s, {bytes=%jd, vol_id=%d}) = %s\n",
     281  		       rsvol_cmds[i].str, (intmax_t) rsvol->bytes,
     282  		       rsvol->vol_id, errstr);
     283  	}
     284  
     285  	TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_set_vol_prop_req, prop);
     286  	fill_memory(prop, sizeof(*prop));
     287  	prop->property = UBI_VOL_PROP_DIRECT_WRITE;
     288  
     289  	for (size_t i = 0; i < ARRAY_SIZE(prop_cmds); ++i) {
     290  		do_ioctl_ptr(prop_cmds[i].cmd, prop);
     291  		printf("ioctl(-1, %s, {property=%s, value=%#jx}) = %s\n",
     292  		       prop_cmds[i].str, "UBI_VOL_PROP_DIRECT_WRITE",
     293  		       (uintmax_t) prop->value, errstr);
     294  	}
     295  
     296  	do_ioctl(_IO(0x6f, 0x35), lmagic);
     297  	printf("ioctl(-1, %s, %#lx) = %s\n", "NET_REMOVE_IF", lmagic, errstr);
     298  
     299  	puts("+++ exited with 0 +++");
     300  	return 0;
     301  }