linux: Fix broken process limits implementation

This commit is contained in:
EnderIce2 2024-10-13 02:19:26 +03:00
parent 02cf233534
commit 93e8e3f354
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
3 changed files with 78 additions and 23 deletions

View File

@ -451,6 +451,7 @@ namespace Tasking
bool IsCritical = false; bool IsCritical = false;
bool IsDebugEnabled = false; bool IsDebugEnabled = false;
bool IsKernelDebugEnabled = false; bool IsKernelDebugEnabled = false;
bool CanAdjustHardLimits = false;
struct struct
{ {
uint16_t UserID = UINT16_MAX; uint16_t UserID = UINT16_MAX;
@ -460,11 +461,17 @@ namespace Tasking
pid_t SessionID = 0; pid_t SessionID = 0;
} Security{}; } Security{};
struct struct
{
rlim_t OpenFiles = 128;
rlim_t Threads = 64;
rlim_t Memory = 1073741824; /* 1 GiB */
} SoftLimits{};
struct
{ {
rlim_t OpenFiles = 4096; rlim_t OpenFiles = 4096;
rlim_t Threads = 1024; rlim_t Threads = 1024;
rlim_t Memory = 8589934592; /* 8 GiB */ rlim_t Memory = 8589934592; /* 8 GiB */
} Limits{}; } HardLimits{};
TaskInfo Info{}; TaskInfo Info{};
ThreadLocalStorage TLS{}; ThreadLocalStorage TLS{};

View File

@ -166,7 +166,7 @@ namespace vfs
{ {
Tasking::PCB *pcb = thisProcess; Tasking::PCB *pcb = thisProcess;
for (size_t i = 0; i < pcb->Limits.OpenFiles; i++) for (size_t i = 0; i < pcb->SoftLimits.OpenFiles; i++)
{ {
auto it = this->FileMap.find(i); auto it = this->FileMap.find(i);
if (it == this->FileMap.end()) if (it == this->FileMap.end())

View File

@ -2687,30 +2687,32 @@ static int linux_prlimit64(SysFrm *, pid_t pid, int resource,
{ {
static_assert(sizeof(struct rlimit) < PAGE_SIZE); static_assert(sizeof(struct rlimit) < PAGE_SIZE);
PCB *pcb = thisProcess; PCB *pcb = nullptr;
Memory::VirtualMemoryArea *vma = pcb->vma; if (likely(pid == 0))
pcb = thisProcess;
else
{
pcb = thisProcess->GetContext()->GetProcessByID(pid);
if (pcb == nullptr)
return -linux_ESRCH;
fixme("implement CAP_SYS_RESOURCE");
return -linux_EPERM;
}
Memory::VirtualMemoryArea *vma = thisProcess->vma;
auto pOldLimit = vma->UserCheckAndGetAddress(old_limit); auto pOldLimit = vma->UserCheckAndGetAddress(old_limit);
auto pNewLimit = vma->UserCheckAndGetAddress(new_limit); auto pNewLimit = vma->UserCheckAndGetAddress(new_limit);
if (pOldLimit == nullptr && old_limit != nullptr) if (pOldLimit == nullptr && old_limit != nullptr)
return -EFAULT; return -linux_EFAULT;
if (pNewLimit == nullptr && new_limit != nullptr) if (pNewLimit == nullptr && new_limit != nullptr)
return -EFAULT; return -linux_EFAULT;
UNUSED(pOldLimit);
UNUSED(pNewLimit);
if (new_limit) if (new_limit)
{ {
debug("new limit: rlim_cur:%lld rlim_max:%lld", if (pNewLimit->rlim_cur > pNewLimit->rlim_max)
pNewLimit->rlim_cur, pNewLimit->rlim_max); return -linux_EINVAL;
}
if (old_limit)
{
debug("old limit: rlim_cur:%lld rlim_max:%lld",
pOldLimit->rlim_cur, pOldLimit->rlim_max);
} }
switch (resource) switch (resource)
@ -2724,22 +2726,70 @@ static int linux_prlimit64(SysFrm *, pid_t pid, int resource,
goto __stub; goto __stub;
case linux_RLIMIT_NPROC: case linux_RLIMIT_NPROC:
{ {
if (old_limit)
{
pOldLimit->rlim_cur = pcb->SoftLimits.Threads;
pOldLimit->rlim_max = pcb->HardLimits.Threads;
debug("read NPROC limit: {%#lx, %#lx}", pOldLimit->rlim_cur, pOldLimit->rlim_max);
}
if (new_limit) if (new_limit)
pcb->Limits.Threads = pNewLimit->rlim_max; {
if (pNewLimit->rlim_max > pcb->HardLimits.Threads && !pcb->Security.CanAdjustHardLimits)
return -linux_EPERM;
debug("setting NPROC limit to {%#lx, %#lx}->{%#lx, %#lx}",
pcb->SoftLimits.Threads, pcb->HardLimits.Threads,
pNewLimit->rlim_cur, pNewLimit->rlim_max);
pcb->SoftLimits.Threads = pNewLimit->rlim_cur;
pcb->HardLimits.Threads = pNewLimit->rlim_max;
}
return 0; return 0;
} }
case linux_RLIMIT_NOFILE: case linux_RLIMIT_NOFILE:
{ {
if (old_limit)
{
pOldLimit->rlim_cur = pcb->SoftLimits.OpenFiles;
pOldLimit->rlim_max = pcb->HardLimits.OpenFiles;
debug("read NOFILE limit: {%#lx, %#lx}", pOldLimit->rlim_cur, pOldLimit->rlim_max);
}
if (new_limit) if (new_limit)
pcb->Limits.OpenFiles = pNewLimit->rlim_max; {
if (pNewLimit->rlim_max > pcb->HardLimits.OpenFiles && !pcb->Security.CanAdjustHardLimits)
return -linux_EPERM;
debug("setting NOFILE limit to {%#lx, %#lx}->{%#lx, %#lx}",
pcb->SoftLimits.OpenFiles, pcb->HardLimits.OpenFiles,
pNewLimit->rlim_cur, pNewLimit->rlim_max);
pcb->SoftLimits.OpenFiles = pNewLimit->rlim_cur;
pcb->HardLimits.OpenFiles = pNewLimit->rlim_max;
}
return 0; return 0;
} }
case linux_RLIMIT_MEMLOCK: case linux_RLIMIT_MEMLOCK:
goto __stub; goto __stub;
case linux_RLIMIT_AS: case linux_RLIMIT_AS:
{ {
if (old_limit)
{
pOldLimit->rlim_cur = pcb->SoftLimits.Memory;
pOldLimit->rlim_max = pcb->HardLimits.Memory;
debug("read AS limit: {%#lx, %#lx}", pOldLimit->rlim_cur, pOldLimit->rlim_max);
}
if (new_limit) if (new_limit)
pcb->Limits.Memory = pNewLimit->rlim_max; {
if (pNewLimit->rlim_max > pcb->HardLimits.Memory && !pcb->Security.CanAdjustHardLimits)
return -linux_EPERM;
debug("setting AS limit to {%#lx, %#lx}->{%#lx, %#lx}",
pcb->SoftLimits.Memory, pcb->HardLimits.Memory,
pNewLimit->rlim_cur, pNewLimit->rlim_max);
pcb->SoftLimits.Memory = pNewLimit->rlim_cur;
pcb->HardLimits.Memory = pNewLimit->rlim_max;
}
return 0; return 0;
} }
case linux_RLIMIT_LOCKS: case linux_RLIMIT_LOCKS:
@ -2757,11 +2807,9 @@ static int linux_prlimit64(SysFrm *, pid_t pid, int resource,
default: default:
{ {
debug("Invalid resource %d", resource); debug("Invalid resource %d", resource);
return -EINVAL; return -linux_EINVAL;
} }
} }
return 0;
} }
static ssize_t linux_getrandom(SysFrm *, void *buf, static ssize_t linux_getrandom(SysFrm *, void *buf,