summaryrefslogtreecommitdiffstats
path: root/0001-redhat-rh_kabi-Add-macros-to-size-and-extend-structs.patch
blob: 616da9edd0132ff7d50c5e80f4a32b380af6da89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Prarit Bhargava <prarit@redhat.com>
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 <ivecera@redhat.com>
RH-Acked-by: Jarod Wilson <jarod@redhat.com>
RH-Acked-by: Jiri Benc <jbenc@redhat.com>

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 <prarit@redhat.com>
Signed-off-by: Jiri Benc <jbenc@redhat.com>
---
 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