(root)/
strace-6.5/
src/
userfaultfd.c
       1  /*
       2   * Copyright (c) 2015 Dmitry V. Levin <ldv@strace.io>
       3   * Copyright (c) 2015-2021 The strace developers.
       4   * All rights reserved.
       5   *
       6   * SPDX-License-Identifier: LGPL-2.1-or-later
       7   */
       8  
       9  #include "defs.h"
      10  #include "kernel_fcntl.h"
      11  #include <linux/ioctl.h>
      12  #include <linux/userfaultfd.h>
      13  
      14  #include "xlat/uffd_flags.h"
      15  
      16  SYS_FUNC(userfaultfd)
      17  {
      18  	printflags(uffd_flags, tcp->u_arg[0], "UFFD_???");
      19  
      20  	return RVAL_DECODED | RVAL_FD;
      21  }
      22  
      23  
      24  #include "xlat/uffd_api_features.h"
      25  #include "xlat/uffd_api_flags.h"
      26  #include "xlat/uffd_copy_flags.h"
      27  #include "xlat/uffd_register_ioctl_flags.h"
      28  #include "xlat/uffd_register_mode_flags.h"
      29  #include "xlat/uffd_zeropage_flags.h"
      30  
      31  static void
      32  tprintf_uffdio_range(const struct uffdio_range *range)
      33  {
      34  	tprint_struct_begin();
      35  	PRINT_FIELD_X(*range, start);
      36  	tprint_struct_next();
      37  	PRINT_FIELD_X(*range, len);
      38  	tprint_struct_end();
      39  }
      40  
      41  int
      42  uffdio_ioctl(struct tcb *const tcp, const unsigned int code,
      43  	     const kernel_ulong_t arg)
      44  {
      45  	switch (code) {
      46  	case UFFDIO_API: {
      47  		uint64_t *entering_features;
      48  		struct uffdio_api ua;
      49  
      50  		if (entering(tcp)) {
      51  			tprint_arg_next();
      52  			if (umove_or_printaddr(tcp, arg, &ua))
      53  				break;
      54  			tprint_struct_begin();
      55  			PRINT_FIELD_X(ua, api);
      56  			tprint_struct_next();
      57  			PRINT_FIELD_FLAGS(ua, features, uffd_api_features,
      58  					  "UFFD_FEATURE_???");
      59  			entering_features = malloc(sizeof(*entering_features));
      60  			if (entering_features) {
      61  				*entering_features = ua.features;
      62  				set_tcb_priv_data(tcp, entering_features, free);
      63  			}
      64  
      65  			return 0;
      66  		}
      67  
      68  		if (!syserror(tcp) && !umove(tcp, arg, &ua)) {
      69  			entering_features = get_tcb_priv_data(tcp);
      70  
      71  			if (!entering_features
      72  			    || *entering_features != ua.features) {
      73  				tprint_value_changed();
      74  				PRINT_FIELD_FLAGS(ua, features,
      75  						  uffd_api_features,
      76  						  "UFFD_FEATURE_???");
      77  			}
      78  
      79  			tprint_struct_next();
      80  			PRINT_FIELD_FLAGS(ua, ioctls, uffd_api_flags,
      81  					  "_UFFDIO_???");
      82  		}
      83  
      84  		tprint_struct_end();
      85  
      86  		break;
      87  	}
      88  
      89  	case UFFDIO_COPY: {
      90  		struct uffdio_copy uc;
      91  
      92  		if (entering(tcp)) {
      93  			tprint_arg_next();
      94  			if (umove_or_printaddr(tcp, arg, &uc))
      95  				return RVAL_IOCTL_DECODED;
      96  			tprint_struct_begin();
      97  			PRINT_FIELD_X(uc, dst);
      98  			tprint_struct_next();
      99  			PRINT_FIELD_X(uc, src);
     100  			tprint_struct_next();
     101  			PRINT_FIELD_X(uc, len);
     102  			tprint_struct_next();
     103  			PRINT_FIELD_FLAGS(uc, mode, uffd_copy_flags,
     104  					  "UFFDIO_COPY_???");
     105  
     106  			return 0;
     107  		}
     108  
     109  		if (!syserror(tcp) && !umove(tcp, arg, &uc)) {
     110  			tprint_struct_next();
     111  			PRINT_FIELD_X(uc, copy);
     112  		}
     113  
     114  		tprint_struct_end();
     115  
     116  		break;
     117  	}
     118  
     119  	case UFFDIO_REGISTER: {
     120  		struct uffdio_register ur;
     121  
     122  		if (entering(tcp)) {
     123  			tprint_arg_next();
     124  			if (umove_or_printaddr(tcp, arg, &ur))
     125  				return RVAL_IOCTL_DECODED;
     126  			tprint_struct_begin();
     127  			PRINT_FIELD_OBJ_PTR(ur, range,
     128  					    tprintf_uffdio_range);
     129  			tprint_struct_next();
     130  			PRINT_FIELD_FLAGS(ur, mode,
     131  					  uffd_register_mode_flags,
     132  					  "UFFDIO_REGISTER_MODE_???");
     133  
     134  			return 0;
     135  		}
     136  
     137  		if (!syserror(tcp) && !umove(tcp, arg, &ur)) {
     138  			tprint_struct_next();
     139  			PRINT_FIELD_FLAGS(ur, ioctls,
     140  					  uffd_register_ioctl_flags,
     141  					  "UFFDIO_???");
     142  		}
     143  
     144  		tprint_struct_end();
     145  
     146  		break;
     147  	}
     148  
     149  	case UFFDIO_UNREGISTER:
     150  	case UFFDIO_WAKE: {
     151  		struct uffdio_range ura;
     152  
     153  		tprint_arg_next();
     154  		if (!umove_or_printaddr(tcp, arg, &ura))
     155  			tprintf_uffdio_range(&ura);
     156  
     157  		break;
     158  	}
     159  
     160  	case UFFDIO_ZEROPAGE: {
     161  		struct uffdio_zeropage uz;
     162  
     163  		if (entering(tcp)) {
     164  			tprint_arg_next();
     165  			if (umove_or_printaddr(tcp, arg, &uz))
     166  				return RVAL_IOCTL_DECODED;
     167  			tprint_struct_begin();
     168  			PRINT_FIELD_OBJ_PTR(uz, range,
     169  					    tprintf_uffdio_range);
     170  			tprint_struct_next();
     171  			PRINT_FIELD_FLAGS(uz, mode, uffd_zeropage_flags,
     172  					  "UFFDIO_ZEROPAGE_???");
     173  
     174  			return 0;
     175  		}
     176  
     177  		if (!syserror(tcp) && !umove(tcp, arg, &uz)) {
     178  			tprint_struct_next();
     179  			PRINT_FIELD_X(uz, zeropage);
     180  		}
     181  
     182  		tprint_struct_end();
     183  
     184  		break;
     185  	}
     186  
     187  	default:
     188  		return RVAL_DECODED;
     189  	}
     190  
     191  	return RVAL_IOCTL_DECODED;
     192  }