"vmsplice()" issue when used with "V4L2 mmap()" method

43 Views Asked by At

Actually, I need to move data from the "mmaped V4L2 buffer" to a "Pipe" in the "User Space".

To ease the debugging, I created a simple test code to mimic the exact situation with the "V4L2" with the same results but using a reserved physical memory range as shown in the shown code.

The Issue:

  • The problem is that I am always getting "Bad Address (14)" error knowing that when I pass the address of a "Memory Region" allocated dynamically using "malloc()", it works fine!

  • I am afraid that "vmsplice()" doesn't work with "Mapped Memory". If so, the alternative such as using "writev()" takes a huge time violating my timing constraints so, what do you recommend in this case?

  • Is this behavior related to "CVE-2008-0600" security vulnerability?

Notes:

  • The "Reserved Memory" is assured to be reserved in the "Device Tree" correctly.
  • All addresses (physical/virtual) are perfectly aligned.
  • "CONFIG_HARDENED_USERCOPY" and "CONFIG_STRICT_DEVMEM" are not set in the kernel.
  • Kernel version = 5.10

Thank you very much.

/*****************************************************************************/
/* INCLUDE FILES                                                             */
/*****************************************************************************/
#ifdef __cplusplus
extern "C"
{
#endif
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdint.h>
#include <errno.h>
#include <stdarg.h>
#include <limits.h>
#include <linux/if_alg.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/uio.h>
#include "Platform_Types.h"
#include <sys/mman.h>
#ifdef __cplusplus
}
#endif


/*****************************************************************************/
/* CONSTANTS, MACROS                                                         */
/*****************************************************************************/
#define u32FRAME_SIZE                               ((uint32_t)(1024U * 1024U))

/*****************************************************************************/
/* TYPES                                                                     */
/*****************************************************************************/


/*****************************************************************************/
/* PRIVATE VARIABLES                                                         */
/*****************************************************************************/
static uint8_t * SysStart_pu8Buffer = NULL;

/*****************************************************************************/
/* PRIVATE FUNCTIONS PROTOTYPES                                              */
/*****************************************************************************/


/*****************************************************************************/
/* PRIVATE FUNCTIONS IMPLEMENTATION                                          */
/*****************************************************************************/
int32_t main(int argc, char *argv[])
{ 
  int32_t fd;
  int s32Error;       
  int as32CrcPipes[2];
  struct iovec iovBufferAddress;
        

  fd = open("/dev/mem", (int32_t)O_RDWR|(int32_t)O_SYNC);
  if(fd != -1)
  {
    printf("[OK] /dev/mem is opened .. \n");
  }

  SysStart_pu8Buffer = (uint8_t*)mmap(0,
                                      0x100000,
                                      (uint8)PROT_READ|(uint8)PROT_WRITE,
                                      (uint8)MAP_SHARED,
                                      fd,
                                      0x85F00000);
  if (SysStart_pu8Buffer != NULL) 
  {
    printf("[OK] Memory Allocation ..\n");
  }

  s32Error = pipe(as32CrcPipes);
  if (s32Error == (int)0) 
  {
    printf("[OK] Pipe Creation ..\n");
  }

  s32Error = fcntl(as32CrcPipes[0], F_SETPIPE_SZ, u32FRAME_SIZE);
  if (s32Error == (int)0) 
  {
    printf("[OK] Pipe Set Size ..\n");
  }

  s32Error = fcntl(as32CrcPipes[1], F_SETPIPE_SZ, u32FRAME_SIZE);
  if (s32Error == (int)0) 
  {
    printf("[OK] Pipe Set Size ..\n");
  }

  iovBufferAddress.iov_base = SysStart_pu8Buffer;
  iovBufferAddress.iov_len = u32FRAME_SIZE;

  ssize_t size =  vmsplice(as32CrcPipes[1], 
                           (const struct iovec *)&iovBufferAddress,
                           (size_t)1, 
                           (unsigned int)SPLICE_F_MOVE);

  if (size < 0)
  {
    printf("[NOK] Error writing buffer to pipe => %s\n", strerror(errno));
  }                            


  return (int32_t)0;
}
0

There are 0 best solutions below