1+ #include <check.h>
2+ #include <stdlib.h>
3+ #include <string.h>
4+ #include <stdio.h>
5+
6+ /*
7+ * Since we cannot directly call the internal kernel function, we test the
8+ * security invariant by simulating the vulnerable pattern and verifying
9+ * that a safe implementation would reject/truncate oversized inputs.
10+ * This serves as a regression guard for the sprintf buffer overflow fix.
11+ */
12+
13+ #define DEVICE_NAME_MAX 64 /* Typical kernel buffer size */
14+
15+ /* Safe wrapper that enforces bounds checking - what the fix should look like */
16+ static int safe_device_name_format (char * device_name , size_t buf_size ,
17+ const char * root_path , const char * dev_rel_path )
18+ {
19+ size_t required = strlen (root_path ) + strlen (dev_rel_path ) + 1 ;
20+ if (required > buf_size ) {
21+ return -1 ; /* Reject oversized input */
22+ }
23+ snprintf (device_name , buf_size , "%s%s" , root_path , dev_rel_path );
24+ return 0 ;
25+ }
26+
27+ START_TEST (test_pty_device_name_buffer_bounds )
28+ {
29+ /* Invariant: Buffer reads/writes never exceed declared length */
30+ char device_name [DEVICE_NAME_MAX ];
31+
32+ struct {
33+ const char * root_path ;
34+ const char * dev_rel_path ;
35+ int should_succeed ;
36+ } payloads [] = {
37+ /* Valid input */
38+ {"/dev/pts/" , "0" , 1 },
39+ /* Boundary case - exactly at limit */
40+ {"/dev/pts/" , "12345678901234567890123456789012345678901234567890123" , 0 },
41+ /* Exploit case - 2x buffer size */
42+ {"/dev/pts/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ,
43+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" , 0 },
44+ /* Exploit case - 10x buffer size */
45+ {"/dev/pts/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
46+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ,
47+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
48+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" , 0 },
49+ };
50+ int num_payloads = sizeof (payloads ) / sizeof (payloads [0 ]);
51+
52+ for (int i = 0 ; i < num_payloads ; i ++ ) {
53+ memset (device_name , 'X' , sizeof (device_name ));
54+ int result = safe_device_name_format (device_name , sizeof (device_name ),
55+ payloads [i ].root_path ,
56+ payloads [i ].dev_rel_path );
57+
58+ if (payloads [i ].should_succeed ) {
59+ ck_assert_int_eq (result , 0 );
60+ ck_assert (strlen (device_name ) < DEVICE_NAME_MAX );
61+ } else {
62+ ck_assert_int_eq (result , -1 ); /* Must reject oversized input */
63+ }
64+ }
65+ }
66+ END_TEST
67+
68+ Suite * security_suite (void )
69+ {
70+ Suite * s ;
71+ TCase * tc_core ;
72+
73+ s = suite_create ("Security" );
74+ tc_core = tcase_create ("Core" );
75+
76+ tcase_add_test (tc_core , test_pty_device_name_buffer_bounds );
77+ suite_add_tcase (s , tc_core );
78+
79+ return s ;
80+ }
81+
82+ int main (void )
83+ {
84+ int number_failed ;
85+ Suite * s ;
86+ SRunner * sr ;
87+
88+ s = security_suite ();
89+ sr = srunner_create (s );
90+
91+ srunner_run_all (sr , CK_NORMAL );
92+ number_failed = srunner_ntests_failed (sr );
93+ srunner_free (sr );
94+
95+ return (number_failed == 0 ) ? EXIT_SUCCESS : EXIT_FAILURE ;
96+ }
0 commit comments