]>
git.saurik.com Git - apple/xnu.git/blob - tests/proc_rlimit.c
3 * xcrun -sdk macosx.internal/iphoneos.internal make proc_rlimit LDFLAGS="-ldarwintest"
7 #include <sys/resource.h>
9 #include <sys/sysctl.h>
10 #include <darwintest.h>
12 /* Defined in <sys/resource.h> but not visible to user space */
13 #define RLIMIT_NLIMITS 9
15 /* Defined in <sys/resource.h> and visible to user space */
16 static const char * RESOURCE_STRING
[] = {
17 "RLIMIT_CPU" , /* #define RLIMIT_CPU 0 */
18 "RLIMIT_FSIZE" , /* #define RLIMIT_FSIZE 1 */
19 "RLIMIT_DATA" , /* #define RLIMIT_DATA 2 */
20 "RLIMIT_STACK" , /* #define RLIMIT_STACK 3 */
21 "RLIMIT_CORE" , /* #define RLIMIT_CORE 4 */
22 "RLIMIT_AS/RSS" , /* #define RLIMIT_AS 5 */
23 /* #define RLIMIT_RSS RLIMIT_AS */
24 "RLIMIT_MEMLOCK" , /* #define RLIMIT_MEMLOCK 6 */
25 "RLIMIT_NPROC" , /* #define RLIMIT_NPROC 7 */
26 "RLIMIT_NOFILE" /* #define RLIMIT_NOFILE 8 */
29 /* Change limit values by this arbitrary amount */
36 /* Action on changing limit values */
40 static struct rlimit orig_rlimit
[ RLIMIT_NLIMITS
];
42 /* Maximum number of open files allowed by normal user */
43 static rlim_t maxfilesperproc
;
44 static size_t maxfilesperproc_size
= sizeof ( maxfilesperproc
);
46 /* Maximum number of open files allowed by super user */
47 static rlim_t maxfiles
;
48 static size_t maxfiles_size
= sizeof ( maxfiles
);
50 /* Maximum number of simultaneous processes allowed by normal user */
51 static rlim_t maxprocperuid
;
52 static size_t maxprocperuid_size
= sizeof ( maxprocperuid
);
54 /* Maximum number of simultaneous processes allowed by super user */
55 static rlim_t maxproc
;
56 static size_t maxproc_size
= sizeof ( maxproc
);
58 static bool superuser
= FALSE
;
61 get_initial_rlimits ( void )
66 for ( i
= 0 ; i
< RLIMIT_NLIMITS
; i
++) {
67 err
= getrlimit ( i
, & orig_rlimit
[ i
]);
68 T_QUIET
; T_EXPECT_EQ ( 0 , err
, "getrlimit( %1 5s, soft: 0x %1 6llx, hard 0x %1 6llx) %s " , RESOURCE_STRING
[ i
], orig_rlimit
[ i
]. rlim_cur
, orig_rlimit
[ i
]. rlim_max
, err
== 0 ? "" : strerror ( errno
));
74 print_rlimits ( bool initial_limits
)
79 for ( i
= 0 ; i
< RLIMIT_NLIMITS
; i
++) {
85 err
= getrlimit ( i
, & lim
);
86 T_QUIET
; T_EXPECT_EQ ( 0 , err
, "getrlimit( %1 5s, soft: 0x %1 6llx, hard 0x %1 6llx) %s " , RESOURCE_STRING
[ i
], lim
. rlim_cur
, lim
. rlim_max
, err
== 0 ? "" : strerror ( errno
));
88 T_LOG ( " %3 5s soft: 0x %1 6llx hard 0x %1 6llx" , RESOURCE_STRING
[ i
], lim
. rlim_cur
, lim
. rlim_max
);
93 * Change "limit_type" of all of the process's "rlimit" by amount
95 * limit_type: SOFT_LIMIT/HARD_LIMIT
100 change_rlimits ( int limit_type
, rlim_t amount
, int action
)
105 for ( i
= 0 ; i
< RLIMIT_NLIMITS
; i
++) {
106 struct rlimit newlim
; // for setrlimit
107 struct rlimit verifylim
; // for getrlimit
108 bool expect_failure
= FALSE
;
109 int expect_errno
= 0 ;
111 /* Get the current limit values */
112 err
= getrlimit ( i
, & newlim
);
113 T_EXPECT_EQ ( 0 , err
, "getrlimit( %1 5s, soft: 0x %1 6llx, hard 0x %1 6llx) %s " , RESOURCE_STRING
[ i
], newlim
. rlim_cur
, newlim
. rlim_max
, err
== 0 ? "" : strerror ( errno
));
115 /* Changing soft limit */
116 if ( limit_type
== SOFT_LIMIT
) {
117 if ( action
== RAISE
) {
118 /* Raising soft limits to exceed hard limits is not allowed and we expect to see failure on setrlimit call later */
119 if ( newlim
. rlim_cur
+ amount
> newlim
. rlim_max
) {
120 expect_failure
= TRUE
;
121 expect_errno
= EINVAL
;
123 newlim
. rlim_cur
+= amount
;
124 } else if ( action
== LOWER
) {
125 if ( newlim
. rlim_cur
== 0 ) {
126 /* Soft limit might be 0 already, if so skip lowering it */
128 newlim
. rlim_cur
-= amount
;
131 T_FAIL ( "Unknown action on soft limit: %d " , action
);
134 /* Changing hard limit */
135 else if ( limit_type
== HARD_LIMIT
) {
136 if ( action
== RAISE
) {
137 newlim
. rlim_max
+= amount
;
139 /* Raising hard limits is not allowed for normal user and we expect to see failure on setrlimit call later */
140 expect_failure
= TRUE
;
141 expect_errno
= EPERM
;
142 } else if ( action
== LOWER
) {
143 if ( newlim
. rlim_max
== 0 ) {
144 /* Hard limit might be 0 already, if so skip lowering it (e.g., RLIMIT_CORE on iOS) */
146 newlim
. rlim_max
-= amount
;
148 /* Soft limit might need to be changed as well since soft cannot be greater than hard */
149 if ( newlim
. rlim_cur
> newlim
. rlim_max
) {
150 newlim
. rlim_cur
= newlim
. rlim_max
;
153 T_FAIL ( "Unknown action on hard limit: %d " , action
);
156 /* Changing unknown limit type */
158 T_FAIL ( "Unknown limit type: %d " , limit_type
);
161 /* Request the kernel to change limit values */
162 err
= setrlimit ( i
, & newlim
);
164 if ( expect_failure
) {
165 /* We expect the setrlimit call to fail */
166 T_EXPECT_EQ (- 1 , err
, "setrlimit( %1 5s, soft: 0x %1 6llx, hard 0x %1 6llx) failed as expected: %s " , RESOURCE_STRING
[ i
], newlim
. rlim_cur
, newlim
. rlim_max
, strerror ( errno
));
167 T_EXPECT_EQ ( expect_errno
, errno
, "Expect errno %d , errno returned %d " , expect_errno
, errno
);
170 T_EXPECT_EQ ( 0 , err
, "setrlimit( %1 5s, soft: 0x %1 6llx, hard 0x %1 6llx) %s " , RESOURCE_STRING
[ i
], newlim
. rlim_cur
, newlim
. rlim_max
, err
== 0 ? "" : strerror ( errno
));
173 /* Verify the kernel correctly changed the limit values */
174 err
= getrlimit ( i
, & verifylim
);
175 T_EXPECT_EQ ( 0 , err
, "getrlimit( %1 5s, soft: 0x %1 6llx, hard 0x %1 6llx) %s " , RESOURCE_STRING
[ i
], verifylim
. rlim_cur
, verifylim
. rlim_max
, err
== 0 ? "" : strerror ( errno
));
177 /* The kernel forces the hard limit of RLIMIT_NOFILE to be at most maxfileperproc for normal user when changing the hard limit with setrlimit */
178 if ( i
== RLIMIT_NOFILE
&& limit_type
== HARD_LIMIT
&& newlim
. rlim_max
> maxfilesperproc
) {
179 if ( newlim
. rlim_cur
!= verifylim
. rlim_cur
||
180 maxfilesperproc
!= verifylim
. rlim_max
) {
181 T_FAIL ( "Mismatch limit values %s despite a successful setrlimit call (setrlimit'd soft 0x %1 6llx hard 0x %1 6llx but getrlimit'd soft 0x %1 6llx hard 0x %1 6llx)" ,
182 RESOURCE_STRING
[ i
], newlim
. rlim_cur
, newlim
. rlim_max
, verifylim
. rlim_cur
, verifylim
. rlim_max
);
185 /* The kernel forces the hard limit of RLIMIT_NPROC to be at most maxproc for normal user when changing either soft/hard limit with setrlimit */
186 else if ( i
== RLIMIT_NPROC
&& newlim
. rlim_max
> maxprocperuid
) {
187 if ( newlim
. rlim_cur
!= verifylim
. rlim_cur
||
188 maxprocperuid
!= verifylim
. rlim_max
) {
189 T_FAIL ( "Mismatch limit values %s despite a successful setrlimit call (setrlimit'd soft 0x %1 6llx hard 0x %1 6llx but getrlimit'd soft 0x %1 6llx hard 0x %1 6llx)" ,
190 RESOURCE_STRING
[ i
], newlim
. rlim_cur
, newlim
. rlim_max
, verifylim
. rlim_cur
, verifylim
. rlim_max
);
193 if ( newlim
. rlim_cur
!= verifylim
. rlim_cur
||
194 newlim
. rlim_max
!= verifylim
. rlim_max
) {
195 T_FAIL ( "Mismatch limit values %s despite a successful setrlimit call (setrlimit'd soft 0x %1 6llx hard 0x %1 6llx but getrlimit'd soft 0x %1 6llx hard 0x %1 6llx)" ,
196 RESOURCE_STRING
[ i
], newlim
. rlim_cur
, newlim
. rlim_max
, verifylim
. rlim_cur
, verifylim
. rlim_max
);
203 "Test basic functionalities of the getrlimit and setrlimit" )
210 if ( geteuid () == 0 ) {
212 T_SKIP ( "This test should not be run as super user." );
215 /* Use sysctl to query the real limits of RLIMIT_NOFILE/RLIMIT_NPROC for normal user on Apple's systems */
216 err
= sysctlbyname ( "kern.maxfilesperproc" , & maxfilesperproc
, & maxfilesperproc_size
, NULL
, 0 );
217 T_EXPECT_EQ_INT ( 0 , err
, "maxfilesperproc: %l lu" , maxfilesperproc
);
219 err
= sysctlbyname ( "kern.maxprocperuid" , & maxprocperuid
, & maxprocperuid_size
, NULL
, 0 );
220 T_EXPECT_EQ_INT ( 0 , err
, "maxprocperuid: %l lu" , maxprocperuid
);
222 /* Use sysctl to query the real limits of RLIMIT_NOFILE/RLIMIT_NPROC for super user on Apple's systems (placeholder for adding super user tests) */
223 err
= sysctlbyname ( "kern.maxfiles" , & maxfiles
, & maxfiles_size
, NULL
, 0 );
224 T_EXPECT_EQ_INT ( 0 , err
, "maxfiles: %l lu" , maxfiles
);
226 err
= sysctlbyname ( "kern.maxproc" , & maxproc
, & maxproc_size
, NULL
, 0 );
227 T_EXPECT_EQ_INT ( 0 , err
, "maxproc: %l lu" , maxproc
);
229 /* Issue getrlimit syscall to retrieve the initial resource limit values before calling setrlimit */
230 err
= get_initial_rlimits ();
231 T_EXPECT_EQ ( 0 , err
, "Obtained initial resource values." );
233 /* Print out resource limit values to stdout for less-painful triage in case needed */
234 T_LOG ( "Resource limits before the test:" );
239 /* Lower soft limits by arbitrary amount */
240 T_LOG ( "---------Lowering soft limits by 0x %x ---------: \n " , LIMIT_DIFF
);
241 change_rlimits ( SOFT_LIMIT
, LIMIT_DIFF
, LOWER
);
243 /* Raise soft limits back to the orginal values */
244 T_LOG ( "---------Raising soft limits by 0x %x ---------: \n " , LIMIT_DIFF
);
245 change_rlimits ( SOFT_LIMIT
, LIMIT_DIFF
, RAISE
);
247 /* Lower hard limits */
248 T_LOG ( "---------Lowering hard limits by 0x %x ---------:" , LIMIT_DIFF
);
249 change_rlimits ( HARD_LIMIT
, LIMIT_DIFF
, LOWER
);
251 /* Raise soft limits to exceed hard limits (setrlimit should fail, but the darwintest should pass) */
252 T_LOG ( "---------Attempting to raised soft limits by 0x %x to exceed hard limits---------:" , LIMIT_DIFF
);
253 change_rlimits ( SOFT_LIMIT
, LIMIT_DIFF
, RAISE
);
255 /* Raise hard limits (setrlimit should fail, but the darwintest should pass) */
256 T_LOG ( "---------Attempting to raise hard limits by 0x %x ---------:" , LIMIT_DIFF
);
257 change_rlimits ( HARD_LIMIT
, LIMIT_DIFF
, RAISE
);
259 /* Get and set a non-existing resource limit */
260 T_LOG ( "---------Accessing a non-existing resource---------:" );
261 err
= getrlimit ( RLIMIT_NLIMITS
+ 1 , & lim
);
262 T_EXPECT_EQ (- 1 , err
, "Expect getrlimit to fail when accessing a non-existing resource: %s \n " , strerror ( errno
));
263 T_EXPECT_EQ ( EINVAL
, errno
, "Expect errno %d , errno returned %d " , EINVAL
, errno
);
265 err
= setrlimit ( RLIMIT_NLIMITS
+ 1 , & lim
);
266 T_EXPECT_EQ (- 1 , err
, "Expect setrlimit to fail when accessing a non-existing resource: %s \n " , strerror ( errno
));
267 T_EXPECT_EQ ( EINVAL
, errno
, "Expect errno %d , errno returned %d " , EINVAL
, errno
);
269 T_LOG ( "Resource limits after the test:" );
270 print_rlimits ( FALSE
);