amd / amd_hsmp

AMD HSMP module to provide user interface to system management features.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

implicit declaration of function ‘copy_struct_from_user’

vysocky opened this issue · comments

The latest version (commit 4276242) of the HSMP is not possible to compile because of the following error:

$ make
make -C /lib/modules/`uname -r`/build M=$PWD modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-1160.53.1.el7.x86_64'
CC [M] /apps/all/AMD_hsmp/42762428221d7304dd12ebc9c724952fa5a5d253/amd_hsmp.o
/apps/all/AMD_hsmp/42762428221d7304dd12ebc9c724952fa5a5d253/amd_hsmp.c: In function ‘hsmp_ioctl’:
/apps/all/AMD_hsmp/42762428221d7304dd12ebc9c724952fa5a5d253/amd_hsmp.c:280:2: error: implicit declaration of function ‘copy_struct_from_user’ [-Werror=implicit-function-declaration]
if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct hsmp_message)))
^
cc1: some warnings being treated as errors
make[2]: *** [/apps/all/AMD_hsmp/42762428221d7304dd12ebc9c724952fa5a5d253/amd_hsmp.o] Error 1
make[1]: *** [_module_/apps/all/AMD_hsmp/42762428221d7304dd12ebc9c724952fa5a5d253] Error 2
make[1]: Leaving directory `/usr/src/kernels/3.10.0-1160.53.1.el7.x86_64'

$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Hi Vysocky

API 'copy_struct_from_user' was introduced to include/linux/uaccess.h header in v5.4 kernel
linux$ git describe f5a1a536fa14895ccff4e94e6a5af90901ce86aa
v5.4-rc1-1-gf5a1a536fa14

It looks like you are trying to build this module in 3.10 kernel. Could you use 'copy_from_user' locally. While, will modify code to use the appropriate API based on kernel version.

I had to add the following block of code extracted from several header files, but it is working

static inline bool should_fail_usercopy(void) { return false; }

static inline bool kasan_check_write(const volatile void *p, unsigned int size)
{
	return true;
}

#define KCSAN_ACCESS_WRITE	(1 << 0) /* Access is a write. */

#define kcsan_check_write(ptr, size)                                           \
	kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE)

static inline void kcsan_check_access(const volatile void *ptr, size_t size,
				      int type) { }

static __always_inline void
instrument_copy_from_user(const void *to, const void __user *from, unsigned long n)
{
	kasan_check_write(to, n);
	kcsan_check_write(to, n);
}


static __always_inline __must_check unsigned long
raw_copy_from_user(void *dst, const void __user *src, unsigned long size)
{
	return copy_user_generic(dst, (__force void *)src, size);
}


#ifdef __LITTLE_ENDIAN
#  define aligned_byte_mask(n) ((1ul << 8*(n))-1)
#else
#  define aligned_byte_mask(n) (~0xfful << (BITS_PER_LONG - 8 - 8*(n)))
#endif

#ifndef user_read_access_begin
#define user_read_access_begin user_access_begin
#define user_read_access_end user_access_end
#endif

#ifndef user_access_begin
#define user_access_begin(ptr,len) access_ok(ptr, len)
#define user_access_end() do { } while (0)
#define unsafe_op_wrap(op, err) do { if (unlikely(op)) goto err; } while (0)
#define unsafe_get_user(x,p,e) unsafe_op_wrap(__get_user(x,p),e)
#define unsafe_put_user(x,p,e) unsafe_op_wrap(__put_user(x,p),e)
#define unsafe_copy_to_user(d,s,l,e) unsafe_op_wrap(__copy_to_user(d,s,l),e)
#define unsafe_copy_from_user(d,s,l,e) unsafe_op_wrap(__copy_from_user(d,s,l),e)
static inline unsigned long user_access_save(void) { return 0UL; }
static inline void user_access_restore(unsigned long flags) { }
#endif



#define access_ok(addr, size)					\
({									\
	WARN_ON_IN_IRQ();						\
	likely(!__range_not_ok(addr, size, TASK_SIZE_MAX));		\
})



int check_zeroed_user(const void __user *from, size_t size)
{
	unsigned long val;
	uintptr_t align = (uintptr_t) from % sizeof(unsigned long);

	if (unlikely(size == 0))
		return 1;

	from -= align;
	size += align;

	if (!user_read_access_begin(from, size))
		return -EFAULT;

	unsafe_get_user(val, (unsigned long __user *) from, err_fault);
	if (align)
		val &= ~aligned_byte_mask(align);

	while (size > sizeof(unsigned long)) {
		if (unlikely(val))
			goto done;

		from += sizeof(unsigned long);
		size -= sizeof(unsigned long);

		unsafe_get_user(val, (unsigned long __user *) from, err_fault);
	}

	if (size < sizeof(unsigned long))
		val &= aligned_byte_mask(size);

done:
	user_read_access_end();
	return (val == 0);
err_fault:
	user_read_access_end();
	return -EFAULT;
}


static __always_inline __must_check int
copy_struct_from_user(void *dst, size_t ksize, const void __user *src,
		      size_t usize)
{
	size_t size = min(ksize, usize);
	size_t rest = max(ksize, usize) - size;

	/* Deal with trailing bytes. */
	if (usize < ksize) {
		memset(dst + size, 0, rest);
	} else if (usize > ksize) {
		int ret = check_zeroed_user(src + size, rest);
		if (ret <= 0)
			return ret ?: -E2BIG;
	}
	/* Copy the interoperable parts of the struct. */
	if (copy_from_user(dst, src, size))
		return -EFAULT;
	return 0;
}

Dear @nchatrad ,
what is the status of this issue? Do you have any expectation when it will be solved?

@vysocky
as mentioned earlier, for older kernel versions prior to v5.4 (where copy_struct_from_user() is not defined). You may use the following change in the driver.

-       if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct hsmp_message)))
+       if (copy_from_user(&msg, arguser, sizeof(struct hsmp_message)))

Note: this driver is accepted https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/commit/?h=for-next&id=91f410aa679a035e7abdff47daca4418c384c770