Skip to content

main: add rlimit support via UCS configuration#14

Open
namansh70747 wants to merge 1 commit intonubificus:mainfrom
namansh70747:feat_rlimits
Open

main: add rlimit support via UCS configuration#14
namansh70747 wants to merge 1 commit intonubificus:mainfrom
namansh70747:feat_rlimits

Conversation

@namansh70747
Copy link
Copy Markdown

Add support for reading and applying resource limits (rlimits) to the
target application as specified in the UCS configuration block.

The UCS block is pre-scanned to count RLIMIT: entries so both arrays
are allocated exactly once. The type string (e.g. RLIMIT_NOFILE) is
resolved to a POSIX resource integer via get_rlimit_vals(). Limits are
applied via setrlimit(2) before privilege drop in setup_exec_env()
and freed on all cleanup paths.

The configuration format is:

UCS
UID:<uid>
GID:<gid>
WD:<working directory>
RLIMIT:<type>:<soft>:<hard>
...
UCE

This is the urunit side of OCI rlimits support. The urunc side that
serializes these entries into URUNIT_CONFIG is in urunc-dev/urunc#558.

Copilot AI review requested due to automatic review settings April 13, 2026 02:33
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for parsing OCI-style RLIMIT: entries from the UCS configuration block and applying them via setrlimit(2) before dropping privileges, enabling urunit-side rlimits support that complements urunc serialization.

Changes:

  • Extend process_config to carry parsed rlimit resources and values.
  • Parse RLIMIT:<type>:<soft>:<hard> lines from UCS and allocate rlimit arrays up-front.
  • Apply parsed rlimits in setup_exec_env() prior to setgid/setuid, and update cleanup paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/main.c
Comment on lines +1126 to +1128
free(app_config->pr_conf->rlimits);
free(app_config->pr_conf->rlimit_resources);
free(app_config->pr_conf);
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

child_func_free dereferences app_config->pr_conf unconditionally. get_config_from_file() can legitimately set econf->pr_conf = NULL (e.g., missing/invalid UCS block), which will segfault here. Guard app_config->pr_conf before freeing its fields (and consider freeing it as a unit in a helper).

Suggested change
free(app_config->pr_conf->rlimits);
free(app_config->pr_conf->rlimit_resources);
free(app_config->pr_conf);
if (app_config->pr_conf) {
free(app_config->pr_conf->rlimits);
free(app_config->pr_conf->rlimit_resources);
free(app_config->pr_conf);
}

Copilot uses AI. Check for mistakes.
Comment thread src/main.c
Comment on lines +548 to +560
while (remaining > 7 && *scan != '\0') {
if (memcmp(scan, "RLIMIT:", 7) == 0)
total_rlimits++;
// Advance to next line
while (remaining > 0 && *scan != '\n' && *scan != '\0') {
scan++;
remaining--;
}
if (remaining > 0 && *scan == '\n') {
scan++;
remaining--;
}
}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RLIMIT pre-scan loop uses while (remaining > 7 && *scan != '\0'), which skips checking a line when exactly 7 bytes remain. If the input ends with a malformed/truncated RLIMIT: line, total_rlimits may stay 0 and later RLIMIT parsing can write via NULL conf->rlimits. Use remaining >= 7 and/or make RLIMIT parsing robust to total_rlimits == 0.

Copilot uses AI. Check for mistakes.
Comment thread src/main.c
Comment on lines +605 to +617
} else if (memcmp(tmp_field, "RLIMIT:", 7) == 0) {
int resource = 0;
rlim_t soft = 0, hard = 0;
ret = get_rlimit_vals(tmp_field, &resource, &soft, &hard);
if (ret != 0) {
fprintf(stderr, "Failed to parse RLIMIT line: %s\n", tmp_field);
break;
}
size_t n = conf->rlimits_count;
conf->rlimits[n].rlim_cur = soft;
conf->rlimits[n].rlim_max = hard;
conf->rlimit_resources[n] = resource;
conf->rlimits_count++;
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When handling RLIMIT: entries, the code writes to conf->rlimits[n] / conf->rlimit_resources[n] without checking that the arrays were allocated and that n is within the allocated capacity. Even if the current pre-scan is expected to over-count, this is still an input-parsing edge case that can become a memory safety bug if the counting logic ever diverges. Track the allocated capacity and validate before writing (fail parsing if exceeded).

Copilot uses AI. Check for mistakes.
Comment thread src/main.c
Comment on lines +1043 to +1046
DEBUG_PRINTF("Setting rlimit resource %d soft=%lu hard=%lu\n",
process_conf->rlimit_resources[i],
(unsigned long)process_conf->rlimits[i].rlim_cur,
(unsigned long)process_conf->rlimits[i].rlim_max);
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEBUG_PRINTF("... soft=%lu hard=%lu") casts rlim_t to unsigned long. On platforms where rlim_t is wider than unsigned long (or on 32-bit builds), this can truncate values and mislead debugging. Prefer printing via uintmax_t/%ju (cast) or use an appropriate format macro for rlim_t.

Suggested change
DEBUG_PRINTF("Setting rlimit resource %d soft=%lu hard=%lu\n",
process_conf->rlimit_resources[i],
(unsigned long)process_conf->rlimits[i].rlim_cur,
(unsigned long)process_conf->rlimits[i].rlim_max);
DEBUG_PRINTF("Setting rlimit resource %d soft=%ju hard=%ju\n",
process_conf->rlimit_resources[i],
(uintmax_t)process_conf->rlimits[i].rlim_cur,
(uintmax_t)process_conf->rlimits[i].rlim_max);

Copilot uses AI. Check for mistakes.
Comment thread src/main.c
Comment on lines +1124 to +1130
if (app_config) {
free(app_config->envs);
free(app_config->pr_conf->rlimits);
free(app_config->pr_conf->rlimit_resources);
free(app_config->pr_conf);
free(app_config);
}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new cleanup frees envs and pr_conf but still doesn't free blk_conf (and the per-entry struct block_config allocations from parse_block_config) on the failure paths where manual_execvpe returns. Since this block is being updated, consider completing the cleanup for blk_conf too to avoid leaks during error handling.

Copilot uses AI. Check for mistakes.
Comment thread src/main.c
ret = setrlimit(process_conf->rlimit_resources[i],
&process_conf->rlimits[i]);
if (ret < 0) {
perror("set rlimit");
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perror("set rlimit") doesn’t match the syscall name (setrlimit) and loses context about which resource failed. Consider using a clearer message (e.g., include the resource id / original type string) so failures are diagnosable from logs.

Suggested change
perror("set rlimit");
char err_msg[64];
snprintf(err_msg, sizeof(err_msg),
"setrlimit(resource %d)",
process_conf->rlimit_resources[i]);
perror(err_msg);

Copilot uses AI. Check for mistakes.
Parse RLIMIT:TYPE:SOFT:HARD entries from the UCS block and apply them
via setrlimit(2) before privilege drop in setup_exec_env().

The type string (e.g. RLIMIT_NOFILE) is resolved to a POSIX resource
integer using a static lookup table. Limits are stored in two parallel
dynamically allocated arrays inside struct process_config: rlimits[]
for the struct rlimit values and rlimit_resources[] for the resource
integers. Both are freed on cleanup.

This is the urunit side of the OCI rlimits feature. The urunc side
that serializes these entries is in urunc-dev/urunc#558.

Signed-off-by: namansh70747 <namansh70747@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants