Merge ~federicoquattrin/qa-regression-testing:add_cjson_tests into qa-regression-testing:master

Proposed by Federico Quattrin
Status: Needs review
Proposed branch: ~federicoquattrin/qa-regression-testing:add_cjson_tests
Merge into: qa-regression-testing:master
Diff against target: 415 lines (+360/-0)
7 files modified
.launchpad.yaml (+15/-0)
scripts/cjson/CVE-2023-50471.c (+25/-0)
scripts/cjson/CVE-2023-50472.c (+15/-0)
scripts/cjson/README.md (+7/-0)
scripts/cjson/bug.c (+33/-0)
scripts/cjson/happy_path.c (+137/-0)
scripts/test-cjson.py (+128/-0)
Reviewer Review Type Date Requested Status
Ubuntu Security Team Pending
Review via email: mp+466195@code.launchpad.net

Commit message

add some cjson tests for CVE-2023-50471 and CVE-2023-50472

Description of the change

add some cjson tests for CVE-2023-50471 and CVE-2023-50472

To post a comment you must log in.
Revision history for this message
Allen Huang (allenpthuang) wrote :

Hi Federico, thanks for the tests! Two small things here: `vm-qrt` seems to need the executable bit set for `test-cjson.py` in order to work properly (and you can see all test-*.py have it set). The other one is you might want to add `gcc` to `QRT-Packages:` too?

Just my 2 ct, thanks again for the tests!

9ba1fd2... by Federico Quattrin

added gcc to QRT-Packages and add the execution bit to test-cjson.py

Revision history for this message
Federico Quattrin (federicoquattrin) wrote (last edit ):

> Hi Federico, thanks for the tests! Two small things here: `vm-qrt` seems to
> need the executable bit set for `test-cjson.py` in order to work properly (and
> you can see all test-*.py have it set). The other one is you might want to add
> `gcc` to `QRT-Packages:` too?
>
> Just my 2 ct, thanks again for the tests!

Hey Allen! Thanks for your feedback! I included your proposal in this commit: https://git.launchpad.net/~federicoquattrin/qa-regression-testing/commit/?id=4c10738d499e90f4e41e5ec6d7de353d78427170.

Thanks!

73e682b... by Federico Quattrin

added cjson in .launchpad.yml

02c29e5... by Federico Quattrin

skip if not 23.10 as USN-6784-1

f63feea... by Federico Quattrin

added mantic to .launchpad.yml for CJSON. Noble is still pending to be added

9868187... by Federico Quattrin

remove mantic from .launchpad.yaml

Unmerged commits

9868187... by Federico Quattrin

remove mantic from .launchpad.yaml

Succeeded
[SUCCEEDED] imagemagick:0 (build)
[SUCCEEDED] imagemagick:1 (build)
[SUCCEEDED] imagemagick:2 (build)
[SUCCEEDED] gcc-security:0 (build)
[SUCCEEDED] gcc-security:1 (build)
[SUCCEEDED] gcc-security:2 (build)
[SUCCEEDED] glibc:0 (build)
[SUCCEEDED] glibc:1 (build)
[SUCCEEDED] glibc:2 (build)
[SUCCEEDED] glibc-security:0 (build)
[SUCCEEDED] glibc-security:1 (build)
[SUCCEEDED] glibc-security:2 (build)
[SUCCEEDED] gnupg:0 (build)
[SUCCEEDED] gnupg:1 (build)
[SUCCEEDED] gnupg:2 (build)
[SUCCEEDED] sudo:0 (build)
[SUCCEEDED] sudo:1 (build)
[SUCCEEDED] sudo:2 (build)
[SUCCEEDED] git:0 (build)
[SUCCEEDED] git:1 (build)
[SUCCEEDED] git:2 (build)
[SUCCEEDED] ghostscript:0 (build)
[SUCCEEDED] ghostscript:1 (build)
[SUCCEEDED] ghostscript:2 (build)
[SUCCEEDED] busybox:0 (build)
[SUCCEEDED] busybox:1 (build)
[SUCCEEDED] busybox:2 (build)
[SUCCEEDED] coreutils:0 (build)
[SUCCEEDED] coreutils:1 (build)
[SUCCEEDED] coreutils:2 (build)
[SUCCEEDED] util-linux:0 (build)
[SUCCEEDED] util-linux:1 (build)
[SUCCEEDED] util-linux:2 (build)
[SUCCEEDED] ecdsautils:0 (build)
[SUCCEEDED] ecdsautils:1 (build)
[SUCCEEDED] ecdsautils:2 (build)
[SUCCEEDED] python-urllib3:0 (build)
[SUCCEEDED] python-urllib3:1 (build)
[SUCCEEDED] python-urllib3:2 (build)
[SUCCEEDED] amanda:0 (build)
[SUCCEEDED] amanda:1 (build)
[SUCCEEDED] cryptojs:0 (build)
[SUCCEEDED] cryptojs:1 (build)
[SUCCEEDED] cryptojs:2 (build)
[SUCCEEDED] samba:0 (build)
[SUCCEEDED] samba:1 (build)
[SUCCEEDED] samba:2 (build)
[SUCCEEDED] cjson:0 (build)
[SUCCEEDED] cjson:1 (build)
149 of 49 results
f63feea... by Federico Quattrin

added mantic to .launchpad.yml for CJSON. Noble is still pending to be added

Failed
[FAILED] imagemagick:0 (build)
[FAILED] imagemagick:1 (build)
[FAILED] imagemagick:2 (build)
[WAITING] gcc-security:0 (build)
[WAITING] gcc-security:1 (build)
[WAITING] gcc-security:2 (build)
[WAITING] glibc:0 (build)
[WAITING] glibc:1 (build)
[WAITING] glibc:2 (build)
[WAITING] glibc-security:0 (build)
[WAITING] glibc-security:1 (build)
[WAITING] glibc-security:2 (build)
[WAITING] gnupg:0 (build)
[WAITING] gnupg:1 (build)
[WAITING] gnupg:2 (build)
[WAITING] sudo:0 (build)
[WAITING] sudo:1 (build)
[WAITING] sudo:2 (build)
[WAITING] git:0 (build)
[WAITING] git:1 (build)
[WAITING] git:2 (build)
[WAITING] ghostscript:0 (build)
[WAITING] ghostscript:1 (build)
[WAITING] ghostscript:2 (build)
[WAITING] busybox:0 (build)
[WAITING] busybox:1 (build)
[WAITING] busybox:2 (build)
[WAITING] coreutils:0 (build)
[WAITING] coreutils:1 (build)
[WAITING] coreutils:2 (build)
[WAITING] util-linux:0 (build)
[WAITING] util-linux:1 (build)
[WAITING] util-linux:2 (build)
[WAITING] ecdsautils:0 (build)
[WAITING] ecdsautils:1 (build)
[WAITING] ecdsautils:2 (build)
[WAITING] python-urllib3:0 (build)
[WAITING] python-urllib3:1 (build)
[WAITING] python-urllib3:2 (build)
[WAITING] amanda:0 (build)
[WAITING] amanda:1 (build)
[WAITING] cryptojs:0 (build)
[WAITING] cryptojs:1 (build)
[WAITING] cryptojs:2 (build)
[WAITING] samba:0 (build)
[WAITING] samba:1 (build)
[WAITING] samba:2 (build)
[WAITING] cjson:0 (build)
[WAITING] cjson:1 (build)
[WAITING] cjson:2 (build)
150 of 50 results
02c29e5... by Federico Quattrin

skip if not 23.10 as USN-6784-1

73e682b... by Federico Quattrin

added cjson in .launchpad.yml

9ba1fd2... by Federico Quattrin

added gcc to QRT-Packages and add the execution bit to test-cjson.py

3eaf0d8... by Federico Quattrin

added some cjson tests

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/.launchpad.yaml b/.launchpad.yaml
index 0c44994..6d5519c 100644
--- a/.launchpad.yaml
+++ b/.launchpad.yaml
@@ -16,6 +16,7 @@ pipeline:
16 - amanda16 - amanda
17 - cryptojs17 - cryptojs
18 - samba18 - samba
19 - cjson
1920
20jobs:21jobs:
21 imagemagick:22 imagemagick:
@@ -259,3 +260,17 @@ jobs:
259 DEBIAN_FRONTEND=noninteractive apt upgrade --assume-yes260 DEBIAN_FRONTEND=noninteractive apt upgrade --assume-yes
260 run: |261 run: |
261 ./lpcraft-runner samba262 ./lpcraft-runner samba
263
264 cjson:
265 matrix:
266 - series: jammy
267 architectures: amd64
268 - series: focal
269 architectures: amd64
270 packages:
271 - sudo
272 run-before: |
273 DEBIAN_FRONTEND=noninteractive apt upgrade --assume-yes
274 run: |
275 ./lpcraft-runner cjson
276
diff --git a/scripts/cjson/CVE-2023-50471.c b/scripts/cjson/CVE-2023-50471.c
262new file mode 100755277new file mode 100755
index 0000000..24ac499
--- /dev/null
+++ b/scripts/cjson/CVE-2023-50471.c
@@ -0,0 +1,25 @@
1#include <cjson/cJSON.h>
2
3
4char * cve_2023_50471(){
5 cJSON *item = cJSON_CreateString("item");
6 cJSON *array = cJSON_CreateArray();
7 cJSON *temp1 = cJSON_CreateString("item1");
8 cJSON *temp2 = cJSON_CreateString("item2");
9
10 cJSON_AddItemToArray(array, temp1);
11 cJSON_AddItemToArray(array, temp2);
12
13 // manually set the prev to be NULL to make a corrupted array
14 temp2->prev = NULL;
15
16 // SEGV as after_inserted->prev is NULL, which is passed to newitem->prev, making newitem->prev->next a NULL pointer using
17 cJSON_InsertItemInArray(array, 1, item);
18
19}
20
21int main(int argc, char **argv){
22
23 cve_2023_50471();
24 return 0;
25}
0\ No newline at end of file26\ No newline at end of file
diff --git a/scripts/cjson/CVE-2023-50472.c b/scripts/cjson/CVE-2023-50472.c
1new file mode 10064427new file mode 100644
index 0000000..be674f4
--- /dev/null
+++ b/scripts/cjson/CVE-2023-50472.c
@@ -0,0 +1,15 @@
1#include <cjson/cJSON.h>
2
3
4char * cve_2023_50472(){
5 cJSON *corruptedItem = cJSON_CreateString("corrupted");
6 corruptedItem->valuestring = NULL;
7 return cJSON_SetValuestring(corruptedItem, "test");
8
9}
10
11int main(int argc, char **argv){
12
13 cve_2023_50472();
14 return 0;
15}
0\ No newline at end of file16\ No newline at end of file
diff --git a/scripts/cjson/README.md b/scripts/cjson/README.md
1new file mode 10064417new file mode 100644
index 0000000..f2e8483
--- /dev/null
+++ b/scripts/cjson/README.md
@@ -0,0 +1,7 @@
1This folder contains scripts to test the cJSON library.
2
3Make sure you install the library by running
4
5sudo apt install libcjson1
6
7
diff --git a/scripts/cjson/bug.c b/scripts/cjson/bug.c
0new file mode 1006448new file mode 100644
index 0000000..2d989e9
--- /dev/null
+++ b/scripts/cjson/bug.c
@@ -0,0 +1,33 @@
1#include <cjson/cJSON.h>
2
3/*
4This file tries to trigger the bug thats fixed here: https://github.com/DaveGamble/cJSON/commit/f66cbab4bfb3926ffd4c5e13f9fb6d506ee0241d
5*/
6
7
8int bug(){
9 cJSON *item = cJSON_CreateString("item");
10 cJSON *array = cJSON_CreateArray();
11 cJSON *temp1 = cJSON_CreateString("item1");
12 cJSON *temp2 = cJSON_CreateString("item2");
13 int ret = -1;
14
15 cJSON_AddItemToArray(array, temp1);
16 cJSON_AddItemToArray(array, temp2);
17
18 // insert item. After this operation array should have 3 items.
19 cJSON_InsertItemInArray(array, 1, item);
20
21 if(cJSON_GetArraySize(array) == 3){
22 ret = 0;
23 }
24
25 // Free the memory allocated for cJSON objects
26 cJSON_Delete(array);
27 return ret;
28
29}
30
31int main(int argc, char **argv){
32 return bug();
33}
0\ No newline at end of file34\ No newline at end of file
diff --git a/scripts/cjson/happy_path.c b/scripts/cjson/happy_path.c
1new file mode 10064435new file mode 100644
index 0000000..e41e186
--- /dev/null
+++ b/scripts/cjson/happy_path.c
@@ -0,0 +1,137 @@
1#include <cjson/cJSON.h>
2#include <stdio.h>
3
4char *create_monitor(void)
5{
6 const unsigned int resolution_numbers[3][2] = {
7 {1280, 720},
8 {1920, 1080},
9 {3840, 2160}
10 };
11 char *string = NULL;
12 cJSON *name = NULL;
13 cJSON *resolutions = NULL;
14 cJSON *resolution = NULL;
15 cJSON *width = NULL;
16 cJSON *height = NULL;
17 size_t index = 0;
18
19 cJSON *monitor = cJSON_CreateObject();
20 if (monitor == NULL)
21 {
22 goto end;
23 }
24
25 name = cJSON_CreateString("Awesome 4K");
26 if (name == NULL)
27 {
28 goto end;
29 }
30 /* after creation was successful, immediately add it to the monitor,
31 * thereby transferring ownership of the pointer to it */
32 cJSON_AddItemToObject(monitor, "name", name);
33
34 resolutions = cJSON_CreateArray();
35 if (resolutions == NULL)
36 {
37 goto end;
38 }
39 cJSON_AddItemToObject(monitor, "resolutions", resolutions);
40
41 for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
42 {
43 resolution = cJSON_CreateObject();
44 if (resolution == NULL)
45 {
46 goto end;
47 }
48 cJSON_AddItemToArray(resolutions, resolution);
49
50 width = cJSON_CreateNumber(resolution_numbers[index][0]);
51 if (width == NULL)
52 {
53 goto end;
54 }
55 cJSON_AddItemToObject(resolution, "width", width);
56
57 height = cJSON_CreateNumber(resolution_numbers[index][1]);
58 if (height == NULL)
59 {
60 goto end;
61 }
62 cJSON_AddItemToObject(resolution, "height", height);
63 }
64
65 string = cJSON_Print(monitor);
66 if (string == NULL)
67 {
68 fprintf(stderr, "Failed to print monitor.\n");
69 }
70
71end:
72 cJSON_Delete(monitor);
73 return string;
74}
75
76/* return 1 if the monitor supports full hd, 0 otherwise */
77int supports_full_hd(const char * const monitor)
78{
79 const cJSON *resolution = NULL;
80 const cJSON *resolutions = NULL;
81 const cJSON *name = NULL;
82 int status = 0;
83 cJSON *monitor_json = cJSON_Parse(monitor);
84 if (monitor_json == NULL)
85 {
86 const char *error_ptr = cJSON_GetErrorPtr();
87 if (error_ptr != NULL)
88 {
89 fprintf(stderr, "Error before: %s\n", error_ptr);
90 }
91 status = 0;
92 goto end;
93 }
94
95 name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name");
96
97 resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
98 cJSON_ArrayForEach(resolution, resolutions)
99 {
100 cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
101 cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height");
102
103 if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height))
104 {
105 status = 0;
106 goto end;
107 }
108
109 if ((width->valuedouble == 1920) && (height->valuedouble == 1080))
110 {
111 status = 1;
112 goto end;
113 }
114 }
115
116end:
117 cJSON_Delete(monitor_json);
118 return status;
119}
120
121
122int happy_path(){
123 if(supports_full_hd(create_monitor())){
124 fprintf(stdout, "Successfully crate and read a JSON.\n");
125 return 0;
126 }
127 else{
128 fprintf(stderr, "Failed crate and read a JSON.\n");
129 return 1;
130 }
131}
132
133
134int main(int argc, char **argv){
135
136 return happy_path();
137}
0\ No newline at end of file138\ No newline at end of file
diff --git a/scripts/test-cjson.py b/scripts/test-cjson.py
1new file mode 100755139new file mode 100755
index 0000000..d67e822
--- /dev/null
+++ b/scripts/test-cjson.py
@@ -0,0 +1,128 @@
1#!/usr/bin/python3
2#
3# test-cjson.py quality assurance test script for cjson
4# Copyright (C) 2024 Canonical Ltd.
5# Author: Federico Quattrin <federico.quattrin@canonical.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3,
9# as published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19
20
21# QRT-Packages: libcjson-dev libcjson1 gcc
22# QRT-Depends: cjson
23
24
25'''
26 In general, this test should be run in a virtual machine (VM) or possibly
27 a chroot and not on a production machine. While efforts are made to make
28 these tests non-destructive, there is no guarantee this script will not
29 alter the machine. You have been warned.
30
31 How to run in a clean VM:
32 $ ./make-test-tarball test-<script>.py # creates tarball in /tmp/
33 $ scp /tmp/qrt-test-<script>.tar.gz root@vm.host:/tmp
34 on VM:
35 # cd /tmp ; tar zxvf ./qrt-test-<script>.tar.gz
36 # cd /tmp/qrt-test-<script> ; ./install-packages ./test-<script>.py
37 # ./test-<script>.py -v
38
39 To run in all VMs named sec*:
40 $ vm-qrt -p sec test-<script.py>
41
42 ### TODO: update for ./install-packages step ###
43 How to run in a clean schroot named 'lucid':
44 $ schroot -c lucid -u root -- sh -c 'apt-get -y install lsb-release <QRT-Packages> && ./test-PKG.py -v'
45'''
46
47from __future__ import print_function
48
49import os
50import subprocess
51import sys
52import unittest
53import testlib
54from string import ascii_letters
55import random
56
57
58
59class TestCJSON(testlib.TestlibCase):
60 '''Test my thing.'''
61
62 def setUp(self):
63 '''Set up prior to each test_* function'''
64 self.output_name = "cjson/cjson_{}".format("".join(random.choice(ascii_letters) for i in range(5)))
65
66
67 def tearDown(self):
68 '''Clean up after each test_* function'''
69 if os.path.isfile(self.output_name):
70 os.remove(self.output_name)
71
72 @unittest.skipIf(
73 testlib.manager.lsb_release['Release'] != 23.10,
74 "Skipping test for Ubuntu {} since updates are in ESM".format(testlib.manager.lsb_release['Release'])
75 )
76 def test_cve_2023_50471(self):
77 '''Test cve_2023_50471'''
78 test_name = "cjson/CVE-2023-50471.c"
79 if not self._compile_test(test_name):
80 raise Exception(f"It was not possible to compile the source code of {test_name}")
81 self.assertTrue(self._execute_test(self.output_name))
82
83 @unittest.skipIf(
84 testlib.manager.lsb_release['Release'] != 23.10,
85 "Skipping test for Ubuntu {} since updates are in ESM".format(testlib.manager.lsb_release['Release'])
86 )
87 def test_cve_2023_50472(self):
88 '''Test cve_2023_50472'''
89 test_name = "cjson/CVE-2023-50472.c"
90 if not self._compile_test(test_name):
91 raise Exception(f"It was not possible to compile the source code of {test_name}")
92 self.assertTrue(self._execute_test(self.output_name))
93
94 def test_happy_path(self):
95 '''Test if we are able to create and read JSON files using CJSON.'''
96 test_name = "cjson/happy_path.c"
97 if not self._compile_test(test_name):
98 raise Exception(f"It was not possible to compile the source code of {test_name}")
99 self.assertTrue(self._execute_test(self.output_name))
100
101 @unittest.skipIf(
102 testlib.manager.lsb_release['Release'] != 23.10,
103 "Skipping test for Ubuntu {} since updates are in ESM".format(testlib.manager.lsb_release['Release'])
104 )
105 def test_cve_2023_50472_bug(self):
106 '''Test if the fix for CVE-2023-50472 has the bug fixed in this commit: https://github.com/DaveGamble/cJSON/commit/f66cbab4bfb3926ffd4c5e13f9fb6d506ee0241d.'''
107 test_name = "cjson/bug.c"
108 if not self._compile_test(test_name):
109 raise Exception(f"It was not possible to compile the source code of {test_name}")
110 self.assertTrue(self._execute_test(self.output_name))
111
112
113 def _compile_test(self, test_name):
114 subprocess.run(['gcc', '-o', self.output_name, test_name, "-lcjson"])
115 if os.path.isfile(self.output_name):
116 return True
117 return False
118
119 @staticmethod
120 def _execute_test(test_name):
121 # give execution rights
122 subprocess.run(['chmod', '+x', test_name])
123 output = subprocess.run([test_name], capture_output=True)
124 return output.returncode == 0
125
126
127if __name__ == '__main__':
128 unittest.main()

Subscribers

People subscribed via source and target branches