From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Wed, 19 Feb 2020 11:52:16 +0100 Subject: [PATCH] redhat: rh_kabi: Add macros to size and extend structs RH-Acked-by: Ivan Vecera RH-Acked-by: Jarod Wilson RH-Acked-by: Jiri Benc Upstream: RHEL-only As noted in the reviews, there are some areas of future work: 1) A further restriction on the access of the extended struct fields would be to require the addition of an accessor function. 2) Additional macros to use RH_KABI_EXTEND fields. 3) Additional macros to mark extended struts' field for internal kernel versus module use. The RHEL7 code contains macros to extend kernel structs. For example, the RH_KABI_EXTEND() can be used to extend a struct when used appropriately. This macro (and others similar to it) has a significant shortcoming as it cannot be used in the case where a struct is known to allocate the struct within a 3rd party module. For example, in RHELX.0, suppose there exists a struct, struct in_kernel { int foo0; }; and an exported function, void in_kernel_set_foo(struct in_kernel *ink) { ... ink->foo0 = 0xBA5EBA11; ... } Let's also suppose a struct in_kernel is statically defined within a 3rd party module, or dynamically allocated as struct in_kernel *3rd_party_ink; ... ink = kmalloc(sizeof(*3rd_party_ink), GFP_KERNEL); ... In RHELX.1, suppose the struct is expanded by struct in_kernel { int foo0; RH_KABI_EXTEND(foo1) }; and the exported function is modified as void in_kernel_set_foo(struct in_kernel *ink) { ... ink->foo0 = 0xBA5EBA11; ink->foo1 = 0xBA5EBA11; ... } The 3rd party module, compiled against RHELX.0, will not have allocated memory for foo1, and in_kernel_set_foo() will reference garbage in memory. To fix this problem, Jiri Benc came up with an great solution that should be unified for all future RHELX.0 expansions of structs. RHEL7 commit e33a3c136b56 ("[net] introduce net_device_ops_extended") adds a size parameter to net_device_ops that can be queried to validate memory accesses. In the patch, net_device_ops is expanded by embedding a net_device_ops_extended struct and addig a size parameter. The size parameter is used to compare the offset of a parameter in the net_device_ops_extended struct to the size of the struct at compile time, and if valid, the memory access can be programmatically allowed to occur. I have taken his idea and created several new standard macros that allow structs to be expanded by embedding a new struct or by adding a pointer to a new struct. There are, however, some rules that must be followed when using these new macros: 1. The default name of the extended struct is ##name##_rh. For example, pci_dev_rh, device_rh, net_device_ops_rh, etc. 2. _rh structs cannot be shrunk in size as such changes would break the size & offset comparison. 3. The size field _must_ be set at the spot of allocation for use. Use of the _rh fields without setting the size field via RH_KABI_SET_SIZE|_PTR() is invalid in the kernel or in a 3rd party module. 4. These new macros do not preclude expansions like struct in_kernel_rh { }; struct in_kernel { ... RH_KABI_EXTEND(void *ptr1) RH_KABI_EXTEND(void *ptr2) RH_KABI_EXTEND(void *ptr3) RH_KABI_EXTEND(void *ptr4) RH_KABI_SIZE_AND_EXTEND_PTR(in_kernel) }; These macros are generally intended for pre-KABI freeze use, however, there may be cases where these macros can be used post-KABI freeze. Due to the design of RH_KABI_EXTEND() which embeds __GENKSYMS__ care must be taken when using RH_KABI_SIZE_AND_EXTEND|_PTR() post-KABI freeze to ensure that structs are not embedded within another struct, verifying offsets, etc. Add RH_KABI_SIZE_AND_EXTEND(), RH_KABI_SIZE_AND_EXTEND_PTR(), and other macros that allow for safe expansion of structs. v2: Cleanup comments. v3: Cleanup comments. Upstream Status: RHEL only Signed-off-by: Prarit Bhargava Signed-off-by: Jiri Benc --- include/linux/rh_kabi.h | 64 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/include/linux/rh_kabi.h b/include/linux/rh_kabi.h index 87f2bd530df7..d551df994583 100644 --- a/include/linux/rh_kabi.h +++ b/include/linux/rh_kabi.h @@ -186,4 +186,68 @@ #define RH_KABI_EXCLUDE(_elem) _RH_KABI_EXCLUDE(_elem); +/* + * RHEL macros to extend structs. + * + * base struct: The struct being extended. For example, pci_dev. + * extended struct: The Red Hat struct being added to the base struct. + * For example, pci_dev_rh. + * + * These macros should be used to extend structs before KABI freeze. + * They can be used post-KABI freeze in the limited case of the base + * struct not being embedded in another struct. + * + * Extended structs cannot be shrunk in size as changes will break + * the size & offset comparison. + * + * Extended struct elements are not guaranteed for access by modules unless + * explicitly commented as such in the declaration of the extended struct or + * the element in the extended struct. + */ + +/* + * RH_KABI_SIZE_AND_EXTEND|_PTR() extends a struct by embedding or adding + * a pointer in a base struct. The name of the new struct is the name + * of the base struct appended with _rh. + */ +#define RH_KABI_SIZE_AND_EXTEND_PTR(_struct) \ + size_t _struct##_size_rh; \ + RH_KABI_EXCLUDE(struct _struct##_rh *_struct##_rh) + +#define RH_KABI_SIZE_AND_EXTEND(_struct) \ + size_t _struct##_size_rh; \ + RH_KABI_EXCLUDE(struct _struct##_rh _struct##_rh) + +/* + * RH_KABI_SET_SIZE calculates and sets the size of the extended struct and + * stores it in the size_rh field for structs that are dynamically allocated. + * This macro MUST be called when expanding a base struct with + * RH_KABI_SIZE_AND_EXTEND, and it MUST be called from the allocation site + * regardless of being allocated in the kernel or a module. + */ +#define RH_KABI_SET_SIZE(_name, _struct) ({ \ + _name._struct##_size_rh = sizeof(struct _struct##_rh); \ +}) + +/* + * RH_KABI_INIT_SIZE calculates and sets the size of the extended struct and + * stores it in the size_rh field for structs that are statically allocated. + * This macro MUST be called when expanding a base struct with + * RH_KABI_SIZE_AND_EXTEND, and it MUST be called from the declaration site + * regardless of being allocated in the kernel or a module. + */ +#define RH_KABI_INIT_SIZE(_struct) \ + ._struct##_size_rh = sizeof(struct _struct##_rh), + +/* + * RH_KABI_CHECK_EXT verifies allocated memory exists. This MUST be called to + * verify that memory in the _rh struct is valid, and can be called + * regardless if RH_KABI_SIZE_AND_EXTEND or RH_KABI_SIZE_AND_EXTEND_PTR is + * used. + */ +#define RH_KABI_CHECK_EXT(_ptr, _struct, _field) ({ \ + size_t __off = offsetof(struct _struct##_rh, _field); \ + _ptr->_struct##_size_rh > __off ? true : false; \ +}) + #endif /* _LINUX_RH_KABI_H */ -- 2.26.2