Skip to content

Commit 8808223

Browse files
Merge pull request #3052 from Pavithra1602/live_patching_2
Test case to verify live patching feature v3
2 parents 8e187b1 + 01a3f49 commit 8808223

File tree

6 files changed

+164
-8
lines changed

6 files changed

+164
-8
lines changed

ras/live_patching.py

Lines changed: 96 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,29 @@ def setUp(self):
5555
self.cancel('%s is needed for the test to be run' % packages)
5656
for file_name in ['test.c', 'libc_livepatch1.c', 'libc_livepatch1.dsc',
5757
'test_2func.c', 'libc_livepatch_2func.c', 'libc_livepatch_2func.dsc',
58-
'Makefile']:
58+
'libc_livepatch_nested.c', 'libc_livepatch_nested.dsc', 'Makefile',
59+
'live_patch_nested.tar.gz', 'test_long.c']:
5960
self.copyutil(file_name)
6061

61-
def apply_livepatch(self, test='test', livepatch='libc_livepatch1.so'):
62+
def start_test(self, test='test'):
6263
"""
63-
function applies a live patch to the running test program and returns
64-
the stderr output
64+
function starts running test program
6565
"""
6666
self.test_process = process.SubProcess(
6767
'LD_PRELOAD=/usr/lib64/libpulp.so.0 ./%s' % test, shell=True, sudo=True)
6868
self.pid = self.test_process.start()
69-
a = self.test_process.get_stderr()
7069
time.sleep(10)
70+
71+
def apply_livepatch(self, livepatch='libc_livepatch1.so'):
72+
"""
73+
function applies a live patch to the running test program and returns
74+
the stderr output
75+
"""
7176
patch_process = process.SubProcess(
7277
'ulp trigger -p %s %s' % (self.pid, livepatch), shell=True, sudo=True)
7378
patch_process.start()
7479
time.sleep(20)
75-
return (self.test_process.get_stderr())
80+
return(self.test_process.get_stderr())
7681

7782
def revert_livepatch(self, livepatch='libc_livepatch1.so'):
7883
"""
@@ -103,6 +108,7 @@ def test_basic(self):
103108
os.chdir(self.teststmpdir)
104109
process.system('make', shell=True)
105110
process.system('ulp packer libc_livepatch1.dsc', shell=True)
111+
self.start_test()
106112
livepatch_output = self.apply_livepatch()
107113
apply_count = self.count_string(livepatch_output)
108114
if apply_count < 10:
@@ -167,10 +173,15 @@ def test_multiple_process_livepatching(self):
167173
self.fail("Livepatch revert failed for %s processes" % (patch_number - patch_revert_number))
168174

169175
def test_two_function_livepatching(self):
176+
"""
177+
This test function ensures that a livepatch with two functions is successfully applied,
178+
both functions are live-patched, and the livepatch can be correctly reverted.
179+
"""
170180
os.chdir(self.teststmpdir)
171181
process.system('make', shell=True)
172182
process.system('ulp packer libc_livepatch_2func.dsc', shell=True)
173-
livepatch_output = self.apply_livepatch('test_2func', 'libc_livepatch_2func.so')
183+
self.start_test('test_2func')
184+
livepatch_output = self.apply_livepatch('libc_livepatch_2func.so')
174185
apply_count = self.count_string(livepatch_output)
175186
apply_count_2 = livepatch_output.count(b'glibc-livepatch-realloc\n')
176187
if apply_count_2 < 10:
@@ -182,3 +193,81 @@ def test_two_function_livepatching(self):
182193
revert_output = self.revert_livepatch('libc_livepatch_2func.so')
183194
if self.count_string(revert_output) - apply_count > 1:
184195
self.fail("Reverting patch is not successful")
196+
197+
def test_nested_function_livepatching(self):
198+
"""
199+
This test function ensures that both a primary livepatch and a nested livepatch
200+
are successfully applied and later reverted.
201+
"""
202+
os.chdir(self.teststmpdir)
203+
process.system('make', shell=True)
204+
process.system('ulp packer libc_livepatch1.dsc', shell=True)
205+
self.start_test()
206+
livepatch_output = self.apply_livepatch()
207+
apply_count_1 = livepatch_output.count(b'glibc-livepatch\n')
208+
if apply_count_1 < 10:
209+
self.fail("Applying first livepatch failed.")
210+
else:
211+
self.log.info("Successfully applied first livepatch")
212+
process.system('ulp packer libc_livepatch_nested.dsc', shell=True)
213+
livepatch_output = self.apply_livepatch('libc_livepatch_nested.so')
214+
time.sleep(10)
215+
apply_count_2 = livepatch_output.count(b'glibc-livepatch-nested\n')
216+
if apply_count_2 < 10:
217+
self.fail("Applying nested livepatch failed.")
218+
else:
219+
self.log.info("Successfully applied nested livepatch")
220+
process.system_output('ulp trigger --revert -p %s libc_livepatch_nested.so' % self.pid, shell=True)
221+
time.sleep(10)
222+
process.system_output('ulp trigger --revert -p %s libc_livepatch1.so' % self.pid, shell=True)
223+
224+
def test_nested_function_livepatching_multiple(self):
225+
"""
226+
This test function ensures that 12 nested livepatches are successfully applied and
227+
later reverted, with each iteration checked for proper application.
228+
"""
229+
os.chdir(self.teststmpdir)
230+
process.system('tar -xf live_patch_nested.tar.gz', shell=True)
231+
process.system('make', shell=True)
232+
self.start_test('test_long')
233+
os.chdir('live_patch_nested')
234+
for i in range(1, 13):
235+
process.system('gcc -fPIC -fpatchable-function-entry=16,14 -shared -o libc_livepatch%s.so'
236+
' libc_livepatch%s.c -msplit-patch-nops' % (i, i), shell=True)
237+
process.system('ulp packer %s/live_patch_nested/libc_livepatch%s.dsc' % (self.teststmpdir, i), shell=True)
238+
livepatch_output = self.apply_livepatch('libc_livepatch%s.so' % i)
239+
for i in range(2, 13):
240+
apply_count = livepatch_output.count(('glibc-livepatch' + str(i)).encode('utf-8'))
241+
if apply_count < 10:
242+
self.fail("Applying livepatch failed for %s iteration." % i)
243+
else:
244+
self.log.info("Successfully applied livepatch for %s iteration" % i)
245+
for i in range(1, 13):
246+
process.system_output('ulp trigger --revert -p %s libc_livepatch%s.so' % (self.pid, i), shell=True)
247+
time.sleep(2)
248+
249+
def test_nested_function_livepatching_multiple2(self):
250+
"""
251+
This test function ensures that 12 nested livepatches are successfully applied and later reverted,
252+
with each iteration checked for proper application. The main difference between this test function and
253+
the previous one is the order of reverting livepatches, which happens in reverse order (from 12 to 1) in this version.
254+
"""
255+
os.chdir(self.teststmpdir)
256+
process.system('tar -xf live_patch_nested.tar.gz', shell=True)
257+
process.system('make', shell=True)
258+
self.start_test('test_long')
259+
os.chdir('live_patch_nested')
260+
for i in range(1, 13):
261+
process.system('gcc -fPIC -fpatchable-function-entry=16,14 -shared -o libc_livepatch%s.so'
262+
' libc_livepatch%s.c -msplit-patch-nops' % (i, i), shell=True)
263+
process.system('ulp packer %s/live_patch_nested/libc_livepatch%s.dsc' % (self.teststmpdir, i), shell=True)
264+
livepatch_output = self.apply_livepatch('libc_livepatch%s.so' % i)
265+
for i in range(2, 13):
266+
apply_count = livepatch_output.count(('glibc-livepatch' + str(i)).encode('utf-8'))
267+
if apply_count < 10:
268+
self.fail("Applying livepatch failed for %s iteration." % i)
269+
else:
270+
self.log.info("Successfully applied livepatch for %s iteration" % i)
271+
for i in range(12, 0, -1):
272+
process.system_output('ulp trigger --revert -p %s libc_livepatch%s.so' % (self.pid, i), shell=True)
273+
time.sleep(2)

ras/live_patching.py.data/Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
1-
all: libc_livepatch1.so test libc_livepatch_2func.so test_2func
1+
all: libc_livepatch1.so test test_long libc_livepatch_2func.so test_2func libc_livepatch_nested.so
22

33
libc_livepatch1.so: libc_livepatch1.c
44
gcc -fPIC -fpatchable-function-entry=16,14 -shared -o libc_livepatch1.so libc_livepatch1.c
55

66
test: test.c
77
gcc -o test test.c
88

9+
test_long: test_long.c
10+
gcc -o test_long test_long.c
11+
912
libc_livepatch_2func.so: libc_livepatch_2func.c
1013
gcc -fPIC -fpatchable-function-entry=16,14 -shared -o libc_livepatch_2func.so libc_livepatch_2func.c
1114

1215
test_2func: test_2func.c
1316
gcc -o test_2func test_2func.c
17+
18+
libc_livepatch_nested.so: libc_livepatch_nested.c
19+
gcc -fPIC -fpatchable-function-entry=16,14 -shared -o libc_livepatch_nested.so libc_livepatch_nested.c
20+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <stdlib.h>
2+
#include <string.h>
3+
4+
#define MIN(x, y) ((x) < (y) ? (x) : (y))
5+
6+
static const char *const lp_string = "glibc-livepatch-nested";
7+
8+
void *malloc_lp_2(size_t s)
9+
{
10+
char *block = calloc(1, s);
11+
if (block && s > 0) {
12+
int lp_string_len = strlen(lp_string);
13+
int copy_len = MIN(lp_string_len + 1, s);
14+
15+
memcpy(block, lp_string, copy_len);
16+
block[s-1] = '\0';
17+
}
18+
return block;
19+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
libc_livepatch_nested.so
2+
@libc_livepatch1.so
3+
malloc_lp:malloc_lp_2
40.7 KB
Binary file not shown.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <unistd.h>
4+
#include <stdbool.h>
5+
#include <string.h>
6+
7+
#define NUM_ATTEMPTS 500
8+
#define LEN 32
9+
10+
static const char *const lp_string = "glibc-livepatch";
11+
12+
int main(int argc, char *argv[])
13+
{
14+
for (int i = 0; i < NUM_ATTEMPTS; i++) {
15+
bool flag = false;
16+
char *m = malloc(LEN);
17+
m[LEN-1] = '\0';
18+
19+
fprintf(stderr, "%s\n", m);
20+
21+
if (m) {
22+
if (!strcmp(m, lp_string)) {
23+
flag = true;
24+
}
25+
free(m);
26+
}
27+
28+
m = calloc(1, 32);
29+
if (m) {
30+
free(m);
31+
} else if (flag) {
32+
return 0;
33+
}
34+
sleep(1);
35+
}
36+
37+
return 1;
38+
}

0 commit comments

Comments
 (0)