Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/src/limits.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 1999-2021 Todd C. Miller <[email protected]>
5
*
6
* Permission to use, copy, modify, and distribute this software for any
7
* purpose with or without fee is hereby granted, provided that the above
8
* copyright notice and this permission notice appear in all copies.
9
*
10
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
*/
18
19
#include <config.h>
20
21
#include <sys/resource.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <unistd.h>
25
#ifdef __linux__
26
# include <sys/prctl.h>
27
#endif
28
#include <ctype.h>
29
#include <errno.h>
30
#include <limits.h>
31
32
#include <sudo.h>
33
34
/*
35
* Avoid using RLIM_INFINITY for the nofile soft limit to prevent
36
* closefrom_fallback() from closing too many file descriptors.
37
*/
38
#if defined(OPEN_MAX) && OPEN_MAX > 256
39
# define SUDO_OPEN_MAX OPEN_MAX
40
#else
41
# define SUDO_OPEN_MAX 256
42
#endif
43
44
#ifdef __LP64__
45
# define SUDO_STACK_MIN (4 * 1024 * 1024)
46
#else
47
# define SUDO_STACK_MIN (2 * 1024 * 1024)
48
#endif
49
50
#ifdef HAVE_SETRLIMIT64
51
# define getrlimit(a, b) getrlimit64((a), (b))
52
# define setrlimit(a, b) setrlimit64((a), (b))
53
# define rlimit rlimit64
54
# define rlim_t rlim64_t
55
# undef RLIM_INFINITY
56
# define RLIM_INFINITY RLIM64_INFINITY
57
#endif /* HAVE_SETRLIMIT64 */
58
59
/* Older BSD systems have RLIMIT_VMEM, not RLIMIT_AS. */
60
#if !defined(RLIMIT_AS) && defined(RLIMIT_VMEM)
61
# define RLIMIT_AS RLIMIT_VMEM
62
#endif
63
64
/*
65
* macOS doesn't allow nofile soft limit to be infinite or
66
* the stack hard limit to be infinite.
67
* Linux containers have a problem with an infinite stack soft limit.
68
*/
69
static struct rlimit stack_fallback = { SUDO_STACK_MIN, 65532 * 1024 };
70
71
static struct saved_limit {
72
const char *name; /* rlimit_foo in lower case */
73
int resource; /* RLIMIT_FOO definition */
74
bool override; /* override limit while sudo executes? */
75
bool saved; /* true if we were able to get the value */
76
bool policy; /* true if policy specified an rlimit */
77
bool preserve; /* true if policy says to preserve user limit */
78
rlim_t minlimit; /* only modify limit if less than this value */
79
struct rlimit *fallback; /* fallback if we fail to set to newlimit */
80
struct rlimit newlimit; /* new limit to use if override is true */
81
struct rlimit oldlimit; /* original limit, valid if saved is true */
82
struct rlimit policylimit; /* limit from policy, valid if policy is true */
83
} saved_limits[] = {
84
#ifdef RLIMIT_AS
85
{
86
"rlimit_as",
87
RLIMIT_AS,
88
true, /* override */
89
false, /* saved */
90
false, /* policy */
91
false, /* preserve */
92
1 * 1024 * 1024 * 1024, /* minlimit */
93
NULL, /* fallback */
94
{ RLIM_INFINITY, RLIM_INFINITY } /* newlimit */
95
},
96
#endif
97
{
98
"rlimit_core",
99
RLIMIT_CORE,
100
false /* override */
101
},
102
{
103
"rlimit_cpu",
104
RLIMIT_CPU,
105
true, /* override */
106
false, /* saved */
107
false, /* policy */
108
false, /* preserve */
109
RLIM_INFINITY, /* minlimit */
110
NULL,
111
{ RLIM_INFINITY, RLIM_INFINITY }
112
},
113
{
114
"rlimit_data",
115
RLIMIT_DATA,
116
true, /* override */
117
false, /* saved */
118
false, /* policy */
119
false, /* preserve */
120
1 * 1024 * 1024 * 1024, /* minlimit */
121
NULL,
122
{ RLIM_INFINITY, RLIM_INFINITY }
123
},
124
{
125
"rlimit_fsize",
126
RLIMIT_FSIZE,
127
true, /* override */
128
false, /* saved */
129
false, /* policy */
130
false, /* preserve */
131
RLIM_INFINITY, /* minlimit */
132
NULL,
133
{ RLIM_INFINITY, RLIM_INFINITY }
134
},
135
#ifdef RLIMIT_LOCKS
136
{
137
"rlimit_locks",
138
RLIMIT_LOCKS,
139
false /* override */
140
},
141
#endif
142
#ifdef RLIMIT_MEMLOCK
143
{
144
"rlimit_memlock",
145
RLIMIT_MEMLOCK,
146
false /* override */
147
},
148
#endif
149
{
150
"rlimit_nofile",
151
RLIMIT_NOFILE,
152
true, /* override */
153
false, /* saved */
154
false, /* policy */
155
false, /* preserve */
156
SUDO_OPEN_MAX, /* minlimit */
157
NULL,
158
{ SUDO_OPEN_MAX, RLIM_INFINITY }
159
},
160
#ifdef RLIMIT_NPROC
161
{
162
"rlimit_nproc",
163
RLIMIT_NPROC,
164
true, /* override */
165
false, /* saved */
166
false, /* policy */
167
false, /* preserve */
168
RLIM_INFINITY, /* minlimit */
169
NULL,
170
{ RLIM_INFINITY, RLIM_INFINITY }
171
},
172
#endif
173
#ifdef RLIMIT_RSS
174
{
175
"rlimit_rss",
176
RLIMIT_RSS,
177
true, /* override */
178
false, /* saved */
179
false, /* policy */
180
false, /* preserve */
181
RLIM_INFINITY, /* minlimit */
182
NULL,
183
{ RLIM_INFINITY, RLIM_INFINITY }
184
},
185
#endif
186
{
187
"rlimit_stack",
188
RLIMIT_STACK,
189
true, /* override */
190
false, /* saved */
191
false, /* policy */
192
false, /* preserve */
193
SUDO_STACK_MIN, /* minlimit */
194
&stack_fallback,
195
{ SUDO_STACK_MIN, RLIM_INFINITY }
196
}
197
};
198
199
static struct rlimit corelimit;
200
static bool coredump_disabled;
201
#ifdef __linux__
202
static struct rlimit nproclimit;
203
static int dumpflag;
204
#endif
205
206
/*
207
* Disable core dumps to avoid dropping a core with user password in it.
208
* Not all operating systems disable core dumps for setuid processes.
209
*/
210
void
211
disable_coredump(void)
212
{
213
debug_decl(disable_coredump, SUDO_DEBUG_UTIL);
214
215
if (getrlimit(RLIMIT_CORE, &corelimit) == 0) {
216
/*
217
* Set the soft limit to 0 but leave the existing hard limit.
218
* On Linux, we need CAP_SYS_RESOURCE to raise the hard limit
219
* which may not be the case in, e.g. an unprivileged container.
220
*/
221
struct rlimit rl = corelimit;
222
rl.rlim_cur = 0;
223
sudo_debug_printf(SUDO_DEBUG_INFO,
224
"RLIMIT_CORE [%lld, %lld] -> [%lld, %lld]",
225
(long long)corelimit.rlim_cur, (long long)corelimit.rlim_max,
226
(long long)rl.rlim_cur, (long long)rl.rlim_max);
227
if (setrlimit(RLIMIT_CORE, &rl) == -1) {
228
sudo_warn("setrlimit(RLIMIT_CORE)");
229
} else {
230
coredump_disabled = true;
231
#ifdef __linux__
232
/* On Linux, also set PR_SET_DUMPABLE to zero (reset by execve). */
233
if ((dumpflag = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) == -1) {
234
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
235
"prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)");
236
dumpflag = 0;
237
}
238
if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
239
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
240
"prctl(PR_SET_DUMPABLE, 0, 0, 0, 0)");
241
}
242
#endif /* __linux__ */
243
}
244
} else {
245
sudo_warn("getrlimit(RLIMIT_CORE)");
246
}
247
248
debug_return;
249
}
250
251
/*
252
* Restore core resource limit before executing the command.
253
*/
254
static void
255
restore_coredump(void)
256
{
257
debug_decl(restore_coredump, SUDO_DEBUG_UTIL);
258
259
if (coredump_disabled) {
260
/*
261
* Do not warn about a failure to restore the core dump size limit.
262
* This is mostly harmless and should not happen in practice.
263
*/
264
if (setrlimit(RLIMIT_CORE, &corelimit) == -1) {
265
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
266
"setrlimit(RLIMIT_CORE, [%lld, %lld])",
267
(long long)corelimit.rlim_cur, (long long)corelimit.rlim_max);
268
}
269
#ifdef __linux__
270
if (prctl(PR_SET_DUMPABLE, dumpflag, 0, 0, 0) == -1) {
271
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
272
"prctl(PR_SET_DUMPABLE, %d, 0, 0, 0)", dumpflag);
273
}
274
#endif /* __linux__ */
275
}
276
debug_return;
277
}
278
279
/*
280
* Unlimit the number of processes since Linux's setuid() will
281
* apply resource limits when changing uid and return EAGAIN if
282
* nproc would be exceeded by the uid switch.
283
*
284
* This function is called *after* session setup and before the
285
* final setuid() call.
286
*/
287
void
288
unlimit_nproc(void)
289
{
290
#ifdef __linux__
291
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
292
debug_decl(unlimit_nproc, SUDO_DEBUG_UTIL);
293
294
if (getrlimit(RLIMIT_NPROC, &nproclimit) != 0)
295
sudo_warn("getrlimit(RLIMIT_NPROC)");
296
sudo_debug_printf(SUDO_DEBUG_INFO, "RLIMIT_NPROC [%lld, %lld] -> [inf, inf]",
297
(long long)nproclimit.rlim_cur, (long long)nproclimit.rlim_max);
298
if (setrlimit(RLIMIT_NPROC, &rl) == -1) {
299
rl.rlim_cur = rl.rlim_max = nproclimit.rlim_max;
300
sudo_debug_printf(SUDO_DEBUG_INFO,
301
"RLIMIT_NPROC [%lld, %lld] -> [%lld, %lld]",
302
(long long)nproclimit.rlim_cur, (long long)nproclimit.rlim_max,
303
(long long)rl.rlim_cur, (long long)rl.rlim_max);
304
if (setrlimit(RLIMIT_NPROC, &rl) != 0)
305
sudo_warn("setrlimit(RLIMIT_NPROC)");
306
}
307
debug_return;
308
#endif /* __linux__ */
309
}
310
311
/*
312
* Restore saved value of RLIMIT_NPROC before execve().
313
*/
314
void
315
restore_nproc(void)
316
{
317
#ifdef __linux__
318
debug_decl(restore_nproc, SUDO_DEBUG_UTIL);
319
320
if (setrlimit(RLIMIT_NPROC, &nproclimit) != 0) {
321
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
322
"setrlimit(RLIMIT_NPROC, [%lld, %lld])",
323
(long long)nproclimit.rlim_cur, (long long)nproclimit.rlim_max);
324
}
325
326
debug_return;
327
#endif /* __linux__ */
328
}
329
330
/*
331
* Unlimit resource limits so sudo is not limited by, e.g.
332
* stack, data or file table sizes.
333
*/
334
void
335
unlimit_sudo(void)
336
{
337
unsigned int idx;
338
int pass, rc;
339
debug_decl(unlimit_sudo, SUDO_DEBUG_UTIL);
340
341
/* Set resource limits to unlimited and stash the old values. */
342
for (idx = 0; idx < nitems(saved_limits); idx++) {
343
struct saved_limit *lim = &saved_limits[idx];
344
if (getrlimit(lim->resource, &lim->oldlimit) == -1)
345
continue;
346
sudo_debug_printf(SUDO_DEBUG_INFO,
347
"getrlimit(%s) -> [%lld, %lld]", lim->name,
348
(long long)lim->oldlimit.rlim_cur,
349
(long long)lim->oldlimit.rlim_max);
350
lim->saved = true;
351
352
/* Only override the existing limit if it is smaller than minlimit. */
353
if (lim->minlimit != RLIM_INFINITY) {
354
if (lim->oldlimit.rlim_cur >= lim->minlimit)
355
lim->override = false;
356
}
357
if (!lim->override)
358
continue;
359
360
for (pass = 0; pass < 2; pass++) {
361
if (lim->newlimit.rlim_cur != RLIM_INFINITY) {
362
/* Don't reduce the soft resource limit. */
363
if (lim->oldlimit.rlim_cur == RLIM_INFINITY ||
364
lim->oldlimit.rlim_cur > lim->newlimit.rlim_cur)
365
lim->newlimit.rlim_cur = lim->oldlimit.rlim_cur;
366
}
367
if (lim->newlimit.rlim_max != RLIM_INFINITY) {
368
/* Don't reduce the hard resource limit. */
369
if (lim->oldlimit.rlim_max == RLIM_INFINITY ||
370
lim->oldlimit.rlim_max > lim->newlimit.rlim_max)
371
lim->newlimit.rlim_max = lim->oldlimit.rlim_max;
372
}
373
if ((rc = setrlimit(lim->resource, &lim->newlimit)) == -1) {
374
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
375
"setrlimit(%s, [%lld, %lld])", lim->name,
376
(long long)lim->newlimit.rlim_cur,
377
(long long)lim->newlimit.rlim_max);
378
if (pass == 0 && lim->fallback != NULL) {
379
/* Try again using fallback values. */
380
lim->newlimit.rlim_cur = lim->fallback->rlim_cur;
381
lim->newlimit.rlim_max = lim->fallback->rlim_max;
382
continue;
383
}
384
}
385
break;
386
}
387
if (rc == -1) {
388
/* Try setting new rlim_cur to old rlim_max. */
389
lim->newlimit.rlim_cur = lim->oldlimit.rlim_max;
390
lim->newlimit.rlim_max = lim->oldlimit.rlim_max;
391
if ((rc = setrlimit(lim->resource, &lim->newlimit)) == -1) {
392
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
393
"setrlimit(%s, [%lld, %lld])", lim->name,
394
(long long)lim->newlimit.rlim_cur,
395
(long long)lim->newlimit.rlim_max);
396
}
397
}
398
if (rc == -1)
399
sudo_warn("setrlimit(%s)", lim->name);
400
}
401
402
debug_return;
403
}
404
405
/*
406
* Restore resource limits modified by unlimit_sudo() and disable_coredump().
407
*/
408
void
409
restore_limits(void)
410
{
411
unsigned int idx;
412
debug_decl(restore_limits, SUDO_DEBUG_UTIL);
413
414
/* Restore resource limits to saved values. */
415
for (idx = 0; idx < nitems(saved_limits); idx++) {
416
struct saved_limit *lim = &saved_limits[idx];
417
if (lim->override && lim->saved) {
418
struct rlimit rl = lim->oldlimit;
419
int i, rc;
420
421
for (i = 0; i < 10; i++) {
422
rc = setrlimit(lim->resource, &rl);
423
if (rc != -1 || errno != EINVAL)
424
break;
425
426
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
427
"setrlimit(%s, [%lld, %lld])", lim->name,
428
(long long)rl.rlim_cur, (long long)rl.rlim_max);
429
430
/*
431
* Soft limit could be lower than current resource usage.
432
* This can be an issue on NetBSD with RLIMIT_STACK and ASLR.
433
*/
434
if (rl.rlim_cur > LLONG_MAX / 2)
435
break;
436
rl.rlim_cur *= 2;
437
if (lim->newlimit.rlim_cur != RLIM_INFINITY &&
438
rl.rlim_cur > lim->newlimit.rlim_cur) {
439
rl.rlim_cur = lim->newlimit.rlim_cur;
440
}
441
if (rl.rlim_max != RLIM_INFINITY &&
442
rl.rlim_cur > rl.rlim_max) {
443
rl.rlim_max = rl.rlim_cur;
444
}
445
rc = setrlimit(lim->resource, &rl);
446
if (rc != -1 || errno != EINVAL)
447
break;
448
}
449
if (rc == -1)
450
sudo_warn("setrlimit(%s)", lim->name);
451
}
452
}
453
restore_coredump();
454
455
debug_return;
456
}
457
458
static bool
459
store_rlimit(const char *str, rlim_t *val, bool soft)
460
{
461
const size_t inflen = sizeof("infinity") - 1;
462
debug_decl(store_rlimit, SUDO_DEBUG_UTIL);
463
464
if (isdigit((unsigned char)*str)) {
465
unsigned long long ullval = 0;
466
char *ep;
467
468
errno = 0;
469
#ifdef HAVE_STRTOULL
470
ullval = strtoull(str, &ep, 10);
471
if (str == ep || (errno == ERANGE && ullval == ULLONG_MAX))
472
debug_return_bool(false);
473
#else
474
ullval = strtoul(str, &ep, 10);
475
if (str == ep || (errno == ERANGE && ullval == ULONG_MAX))
476
debug_return_bool(false);
477
#endif
478
if (*ep == '\0' || (soft && *ep == ',')) {
479
*val = ullval;
480
debug_return_bool(true);
481
}
482
goto done;
483
}
484
if (strncmp(str, "infinity", inflen) == 0) {
485
if (str[inflen] == '\0' || (soft && str[inflen] == ',')) {
486
*val = RLIM_INFINITY;
487
debug_return_bool(true);
488
}
489
}
490
done:
491
debug_return_bool(false);
492
}
493
494
static bool
495
set_policy_rlimit(int resource, const char *val)
496
{
497
unsigned int idx;
498
debug_decl(set_policy_rlimit, SUDO_DEBUG_UTIL);
499
500
for (idx = 0; idx < nitems(saved_limits); idx++) {
501
struct saved_limit *lim = &saved_limits[idx];
502
const char *hard, *soft = val;
503
504
if (lim->resource != resource)
505
continue;
506
507
if (strcmp(val, "default") == 0) {
508
/* Use system-assigned limit set by begin_session(). */
509
lim->policy = false;
510
lim->preserve = false;
511
debug_return_bool(true);
512
}
513
if (strcmp(val, "user") == 0) {
514
/* Preserve invoking user's limit. */
515
lim->policy = false;
516
lim->preserve = true;
517
debug_return_bool(true);
518
}
519
520
/*
521
* Expect limit in the form "soft,hard" or "limit" (both soft+hard).
522
*/
523
hard = strchr(val, ',');
524
if (hard != NULL)
525
hard++;
526
else
527
hard = soft;
528
529
if (store_rlimit(soft, &lim->policylimit.rlim_cur, true) &&
530
store_rlimit(hard, &lim->policylimit.rlim_max, false)) {
531
lim->policy = true;
532
lim->preserve = false;
533
debug_return_bool(true);
534
}
535
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
536
"%s: invalid rlimit: %s", lim->name, val);
537
debug_return_bool(false);
538
}
539
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
540
"invalid resource limit: %d", resource);
541
debug_return_bool(false);
542
}
543
544
bool
545
parse_policy_rlimit(const char *str)
546
{
547
bool ret = false;
548
debug_decl(parse_policy_rlimit, SUDO_DEBUG_UTIL);
549
550
#ifdef RLIMIT_AS
551
if (strncmp(str, "as=", sizeof("as=") - 1) == 0) {
552
str += sizeof("as=") - 1;
553
ret = set_policy_rlimit(RLIMIT_AS, str);
554
} else
555
#endif
556
#ifdef RLIMIT_CORE
557
if (strncmp(str, "core=", sizeof("core=") - 1) == 0) {
558
str += sizeof("core=") - 1;
559
ret = set_policy_rlimit(RLIMIT_CORE, str);
560
} else
561
#endif
562
#ifdef RLIMIT_CPU
563
if (strncmp(str, "cpu=", sizeof("cpu=") - 1) == 0) {
564
str += sizeof("cpu=") - 1;
565
ret = set_policy_rlimit(RLIMIT_CPU, str);
566
} else
567
#endif
568
#ifdef RLIMIT_DATA
569
if (strncmp(str, "data=", sizeof("data=") - 1) == 0) {
570
str += sizeof("data=") - 1;
571
ret = set_policy_rlimit(RLIMIT_DATA, str);
572
} else
573
#endif
574
#ifdef RLIMIT_FSIZE
575
if (strncmp(str, "fsize=", sizeof("fsize=") - 1) == 0) {
576
str += sizeof("fsize=") - 1;
577
ret = set_policy_rlimit(RLIMIT_FSIZE, str);
578
} else
579
#endif
580
#ifdef RLIMIT_LOCKS
581
if (strncmp(str, "locks=", sizeof("locks=") - 1) == 0) {
582
str += sizeof("locks=") - 1;
583
ret = set_policy_rlimit(RLIMIT_LOCKS, str);
584
} else
585
#endif
586
#ifdef RLIMIT_MEMLOCK
587
if (strncmp(str, "memlock=", sizeof("memlock=") - 1) == 0) {
588
str += sizeof("memlock=") - 1;
589
ret = set_policy_rlimit(RLIMIT_MEMLOCK, str);
590
} else
591
#endif
592
#ifdef RLIMIT_NOFILE
593
if (strncmp(str, "nofile=", sizeof("nofile=") - 1) == 0) {
594
str += sizeof("nofile=") - 1;
595
ret = set_policy_rlimit(RLIMIT_NOFILE, str);
596
} else
597
#endif
598
#ifdef RLIMIT_NPROC
599
if (strncmp(str, "nproc=", sizeof("nproc=") - 1) == 0) {
600
str += sizeof("nproc=") - 1;
601
ret = set_policy_rlimit(RLIMIT_NPROC, str);
602
} else
603
#endif
604
#ifdef RLIMIT_RSS
605
if (strncmp(str, "rss=", sizeof("rss=") - 1) == 0) {
606
str += sizeof("rss=") - 1;
607
ret = set_policy_rlimit(RLIMIT_RSS, str);
608
} else
609
#endif
610
#ifdef RLIMIT_STACK
611
if (strncmp(str, "stack=", sizeof("stack=") - 1) == 0) {
612
str += sizeof("stack=") - 1;
613
ret = set_policy_rlimit(RLIMIT_STACK, str);
614
}
615
#endif
616
debug_return_bool(ret);
617
}
618
619
/*
620
* Set resource limits as specified by the security policy (if any).
621
* This should be run as part of the session setup but after PAM,
622
* login.conf, etc.
623
*/
624
void
625
set_policy_rlimits(void)
626
{
627
unsigned int idx;
628
debug_decl(set_policy_rlimits, SUDO_DEBUG_UTIL);
629
630
for (idx = 0; idx < nitems(saved_limits); idx++) {
631
struct saved_limit *lim = &saved_limits[idx];
632
struct rlimit *rl;
633
int rc;
634
635
if (!lim->policy && (!lim->preserve || !lim->saved))
636
continue;
637
638
rl = lim->preserve ? &lim->oldlimit : &lim->policylimit;
639
if ((rc = setrlimit(lim->resource, rl)) == 0) {
640
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
641
"setrlimit(%s, [%lld, %lld])", lim->name,
642
(long long)rl->rlim_cur, (long long)rl->rlim_max);
643
continue;
644
}
645
646
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
647
"setrlimit(%s, [%lld, %lld])", lim->name,
648
(long long)rl->rlim_cur, (long long)rl->rlim_max);
649
650
if (rl->rlim_cur > lim->oldlimit.rlim_max || rl->rlim_max > lim->oldlimit.rlim_max) {
651
/* Try setting policy rlim_cur to old rlim_max. */
652
if (rl->rlim_cur > lim->oldlimit.rlim_max)
653
rl->rlim_cur = lim->oldlimit.rlim_max;
654
if (rl->rlim_max > lim->oldlimit.rlim_max)
655
rl->rlim_max = lim->oldlimit.rlim_max;
656
if ((rc = setrlimit(lim->resource, rl)) == -1) {
657
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
658
"setrlimit(%s, [%lld, %lld])", lim->name,
659
(long long)rl->rlim_cur, (long long)rl->rlim_max);
660
}
661
}
662
if (rc == -1)
663
sudo_warn("setrlimit(%s)", lim->name);
664
}
665
666
debug_return;
667
}
668
669
size_t
670
serialize_rlimits(char **info, size_t info_max)
671
{
672
char *str;
673
size_t idx, nstored = 0;
674
debug_decl(serialize_rlimits, SUDO_DEBUG_UTIL);
675
676
for (idx = 0; idx < nitems(saved_limits); idx++) {
677
const struct saved_limit *lim = &saved_limits[idx];
678
const struct rlimit *rl = &lim->oldlimit;
679
char curlim[STRLEN_MAX_UNSIGNED(unsigned long long) + 1];
680
char maxlim[STRLEN_MAX_UNSIGNED(unsigned long long) + 1];
681
682
if (!lim->saved)
683
continue;
684
685
if (nstored == info_max)
686
goto oom;
687
688
if (rl->rlim_cur == RLIM_INFINITY) {
689
strlcpy(curlim, "infinity", sizeof(curlim));
690
} else {
691
snprintf(curlim, sizeof(curlim), "%llu",
692
(unsigned long long)rl->rlim_cur);
693
}
694
if (rl->rlim_max == RLIM_INFINITY) {
695
strlcpy(maxlim, "infinity", sizeof(maxlim));
696
} else {
697
snprintf(maxlim, sizeof(maxlim), "%llu",
698
(unsigned long long)rl->rlim_max);
699
}
700
if (asprintf(&str, "%s=%s,%s", lim->name, curlim, maxlim) == -1)
701
goto oom;
702
info[nstored++] = str;
703
}
704
debug_return_size_t(nstored);
705
oom:
706
while (nstored)
707
free(info[--nstored]);
708
debug_return_size_t((size_t)-1);
709
}
710
711