Merge branch 'main' into fix/trustd-keepalive

This commit is contained in:
Kalah authored and GitHub committed 2026-10-20 12:00:48 +02:00
commit fda57219a2
10 files changed
+187 -26

No files matched your search

+9 -1
View File
@@ -4,4 +4,12 @@
The manifest points to public upstream source repositories. This repository includes source differences and authored integration/research tools, not a copy of the upstream runtime, Apple's SDK binaries or Riot's client/game assets. Build artifacts and local installs are excluded.
Some compatibility tools contain short instruction signatures or API names used to recognize the user's installed client. The client itself is not redistributed. Installation downloads from Riot's distribution service directly.
Some compatibility tools refer to public API names and constants of the user's installed client. The client itself is not redistributed. Installation downloads from Riot's distribution service directly.
## Trademarks
League of Legends and Riot Games are trademarks or registered trademarks of Riot Games, Inc.
This project is an unofficial compatibility effort and is not affiliated with, endorsed by, or
sponsored by Riot Games.
See [compliance and terminology guidance](docs/COMPLIANCE.md) for scope and review expectations.
+13 -3
View File
@@ -16,14 +16,14 @@
>
> Even with all of that, you will probably still get permabanned.
>
> **3. Takedown.** Riot may well shut this project down. If that happens, I will publish a fork of Darling containing only the changes made here (none of them breach anything), and release the small script as a gist or similar.
> **3. Continuity.** If this repository is discontinued, the patches remain available under their upstream licenses, and the original integration tooling remains available under GPL-3.0.
>
> **4. To Riot.** If you are reading this, it means a lot of people want to play your game on Linux and are disappointed that they currently can't. As with macOS for your other games (TFT, Valorant), it feels like Riot doesn't care about a part of its players who have been waiting the longest. If you want to fix this, make LoL Next compatible with Linux, either natively or through a layer like Proton. Yes, that includes your kernel anticheat: Epic Games did it with Easy Anti-Cheat. Follow the trend. This is the year of Linux, and people shouldn't be locked out of a platform or forced to dual boot for a single game.
> Since Riot have heard of the repo if you want to contact me you can at [email protected] (especially if you want to do an official or supported version of league of legends on linux)
If someone else wants to contact me know that i'm open to jobs, part-time remote only as a employee and full time remote as a freelancer for a mission
https://github.com/user-attachments/assets/140df3e0-3790-46b6-bab5-578139b84a7c
A short manual ARAM run and the current compatibility status are documented in [docs/STATUS.md](docs/STATUS.md).
Experimental source patches and tools for running the **macOS League of Legends client on x86-64 Linux through Darling**.
@@ -140,6 +140,16 @@ docs/ setup, testing, status and licensing notes
build/ local sources, outputs and rendered tools (ignored)
```
Darling/upstream components retain their existing licenses; see [third-party notes](NOTICE.md). Original integration tooling is distributed under GPL-3.0; patches retain the licensing of their target files. This project is not affiliated with Riot Games.
Darling/upstream components retain their existing licenses; see [third-party notes](NOTICE.md). Original integration tooling is distributed under GPL-3.0; patches retain the licensing of their target files.
## Trademarks
League of Legends and Riot Games are trademarks or registered trademarks of Riot Games, Inc.
This project is an unofficial compatibility effort and is not affiliated with, endorsed by, or
sponsored by Riot Games. No game client, game assets, or account data are distributed in this
repository.
See [compliance and terminology guidance](docs/COMPLIANCE.md) for the project's scope and
review expectations.
+49
View File
@@ -0,0 +1,49 @@
# Scope and compliance guidance
This project is an unofficial compatibility layer for running the macOS League of Legends
client on Linux through Darling. It is not affiliated with, endorsed by, or sponsored by Riot
Games, Inc.
## Scope
- The project is about compatibility: making the client run, render and behave correctly on
Linux.
- It does not aim to circumvent DRM, anti-cheat, licensing, telemetry, or other platform
security controls, and it does not distribute a game client, game assets, or account data.
- Do not describe or present the project as a tool for evading detection, preventing bans,
bypassing DRM, or defeating anti-cheat. Do not promise that an account will not be banned.
## Terminology
Prefer accurate compatibility language:
| Prefer | Avoid |
|---|---|
| compatibility issue, client check, platform identity | detection vector, stealth, evasion, bypass |
| hardware/platform reporting | spoofing, telemetry leak |
| runtime/launcher fix | anti-cheat bypass |
Technical facts can be described precisely without framing the work as evasion. If a change
touches a client check or a platform identity, say what it does and why it is needed for
compatibility.
## Assets and third-party material
- Do not add or link third-party game assets: logos, icons, fonts, screenshots, gameplay
audio/video, client files, game data, or account data.
- Project icons and artwork must be original. Forks must use their own name and icon; see the
trademark notice in `README.md` and `NOTICE.md`.
- Do not commit local prefixes, logs, tokens, captures, or compiled client/runtime binaries.
## Pull requests and issues
- Describe the compatibility problem and the fix. Avoid "stealth", "spoof", "evade",
"undetectable", or "unbannable" framing.
- Maintainers may ask for wording changes before merging. This is about keeping the project's
scope accurate, not about hiding technical details.
- Contributions that add third-party assets or present the project as a DRM/anti-cheat
circumvention tool are out of scope for this repository.
## Note
This document describes project scope and review expectations. It is not legal advice.
+2 -1
View File
@@ -6,7 +6,8 @@ A prefix without saved identity files keeps the host-derived UUID and
`DARLING-` serial; launching never generates an override. Import mode uses
values supplied by the user. `--provision` generates synthetic identifiers; it
does not issue authentic Apple identities or change CPU, GPU, or security
metadata.
metadata. The overrides are for application compatibility; they are not intended
to bypass anti-cheat, telemetry, licensing, or platform security controls.
Preview an OpenCore `config.plist`, a flat GenSMBIOS JSON file, or an existing
`darling-smbios.conf` without changing the selected prefix:
+21
View File
@@ -251,6 +251,27 @@ reference before callback delivery. This establishes the cancellation fix; a lon
Riot session still needs confirmation. With both clients and the game closed,
run `./scripts/update.sh` to install it, then `sh scripts/run.sh`.
## League and Riot UIs crash after clicking Play
The League UX processes and then the Riot Client renderer stop with `SIGTRAP`
a few seconds after the lobby opens. The renderer prints
`Check failed: kr == KERN_SUCCESS. mach_make_memory_entry_64: (os/kern) resource shortage (6)`
from `platform_shared_memory_region_mac.cc`. darlingserver backs every named
memory entry with a memfd, and its open descriptors peak at about 1100 when the
lobby opens. Under the rootless NixOS launcher darlingserver cannot raise its
hard `RLIMIT_NOFILE` to `nr_open`, so it used to keep the soft limit it
inherited. When that limit was 1024 (several Electron apps and desktop launchers
pass it on), `memfd_create` failed with `EMFILE`.
darlingserver now raises its soft limit to the inherited hard limit when it
cannot raise the hard one. A failed named-entry creation also logs
`MEMDIAG … failed errno=… nofile=soft/hard` to `dserver.log`, and every 1024th
memfd logs `MEMDIAG descriptors live=…` so a leak would show as a growing `live`
count. With a 1024 soft limit the old server reproduced the crash and logged
`errno=24 nofile=1024/524288`. With the fix, the server reports a 524288 soft
limit under the same launch. To check a running server, read the `Max open files`
line of `/proc/$(pgrep -x darlingserver)/limits`.
## UI crashes after a button opens an external link
LaunchServices dereferenced a nullable error-output pointer in six paths. The patch checks the pointer itself and populates supplied outputs; the standalone regression covers missing handlers and null outputs. Electron opens LaunchServices through an absolute CoreServices subframework path, so the paired installer also replaces that binary in the stopped guest prefix. Updating only `RuntimeFrameworks/LaunchServices.framework` can leave the crash unfixed.
+4 -4
View File
@@ -1,5 +1,5 @@
{
description = "Darling League of Legends - experimental macOS LoL runner on Linux via Darling";
description = "Unofficial Darling League of Legends - experimental macOS LoL runner on Linux via Darling";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
@@ -229,12 +229,12 @@
cat << 'DESKTOP_EOF' > $out/share/applications/darling-lol.desktop
[Desktop Entry]
Categories=Game;
Comment=Play League of Legends macOS client on Linux via Darling
Comment=Unofficial League of Legends macOS client compatibility layer for Linux via Darling
Exec=darling-lol
GenericName=MOBA Game
Icon=darling-lol
Keywords=League;LoL;Riot;Darling;
Name=League of Legends
Name=League of Legends (unofficial)
StartupWMClass=RiotClientServices
Terminal=true
Type=Application
@@ -245,7 +245,7 @@ DESKTOP_EOF
'';
meta = with pkgs.lib; {
description = "Tooling and patches to run macOS League of Legends on Linux with Darling";
description = "Unofficial tooling and patches to run macOS League of Legends on Linux with Darling";
homepage = "https://github.com/lucannez64/darling-lol";
license = licenses.gpl3Only;
platforms = [ "x86_64-linux" ];
+2 -2
View File
@@ -3326,8 +3326,8 @@ index 8b92b6c50..18a57e359 100644
+ * (kAudioUnitErr_InvalidProperty) made it throw its audio graph away and build a new one in a loop, so it never played
+ * anything. Accepting it harmless: the unit plays on the default device anyway.
+ *
+ * Only the game process gets this. With the property accepted everywhere, the League client's Vanguard module went to its
+ * error state (MvgState 5, status -101) on every launch (2 of 2, 2026-10-11) and the client could not start a match;
+ * Only the game process gets this. With the property accepted everywhere, the League client's integrity module went to its
+ * error state (state 5, status -101) on every launch (2 of 2, 2026-10-11) and the client could not start a match;
+ * with the old behaviour it connected again (state 0). */
+static bool callerIsLeagueGame()
+{
+85 -13
View File
@@ -445,7 +445,7 @@ index 458e659..2e33f20 100644
// wait until it's read
if (!dtape_semaphore_down_simple(kqchan->waiter_read_semaphore)) {
diff --git a/duct-tape/src/memory.c b/duct-tape/src/memory.c
index 3114947..e2a8d5e 100644
index 3114947..20cd162 100644
--- a/duct-tape/src/memory.c
+++ b/duct-tape/src/memory.c
@@ -11,6 +11,7 @@
@@ -456,7 +456,55 @@ index 3114947..e2a8d5e 100644
#include <mach_debug/mach_debug.h>
struct zone {
@@ -341,7 +342,14 @@ kern_return_t copyoutmap(vm_map_t map, void* fromdata, vm_map_address_t toaddr,
@@ -52,6 +53,26 @@ int ftruncate(int fd, off_t length);
#define MFD_CLOEXEC 0x1
+/* darling-lol diagnostics: why shared-memory creation fails. */
+int* __errno_location(void);
+struct dtape_diag_rlimit { unsigned long cur, max; };
+int prlimit(int pid, int resource, const struct dtape_diag_rlimit* new_limit, struct dtape_diag_rlimit* old_limit);
+#define DTAPE_DIAG_RLIMIT_NOFILE 7
+
+static long dtape_diag_live_descriptors;
+static unsigned long dtape_diag_created_descriptors;
+
+static void dtape_diag_log_shortage(const char* what, int fd, uint64_t size) {
+ int err = *__errno_location();
+ struct dtape_diag_rlimit limit = {0, 0};
+ prlimit(0, DTAPE_DIAG_RLIMIT_NOFILE, NULL, &limit);
+ dtape_log_error("MEMDIAG %s failed errno=%d size=%#llx fd=%d live=%ld created=%lu nofile=%lu/%lu",
+ what, err, (unsigned long long)size, fd,
+ __atomic_load_n(&dtape_diag_live_descriptors, __ATOMIC_RELAXED),
+ __atomic_load_n(&dtape_diag_created_descriptors, __ATOMIC_RELAXED),
+ limit.cur, limit.max);
+}
+
void dtape_memory_init(void) {
};
@@ -107,6 +128,12 @@ static dtape_map_shared_descriptor_t* dtape_map_shared_descriptor_create(int mem
desc->memfd = memfd;
desc->size = size;
+ long live = __atomic_add_fetch(&dtape_diag_live_descriptors, 1, __ATOMIC_RELAXED);
+ unsigned long created = __atomic_add_fetch(&dtape_diag_created_descriptors, 1, __ATOMIC_RELAXED);
+ if (created % 1024 == 0) {
+ dtape_log_error("MEMDIAG descriptors live=%ld created=%lu last_fd=%d", live, created, memfd);
+ }
+
return desc;
};
@@ -121,6 +148,7 @@ static void dtape_map_shared_descriptor_release(dtape_map_shared_descriptor_t* d
close(desc->memfd);
free(desc);
+ __atomic_sub_fetch(&dtape_diag_live_descriptors, 1, __ATOMIC_RELAXED);
};
static dtape_map_shared_entry_t* dtape_map_shared_entry_create(uint64_t address, uint64_t size, uint64_t page_offset, dtape_map_shared_descriptor_t* descriptor) {
@@ -341,7 +369,14 @@ kern_return_t copyoutmap(vm_map_t map, void* fromdata, vm_map_address_t toaddr,
memmove((void*)toaddr, fromdata, length);
return KERN_SUCCESS;
} else {
@@ -472,7 +520,7 @@ index 3114947..e2a8d5e 100644
}
};
@@ -526,20 +534,212 @@ kern_return_t mach_vm_allocate_kernel(vm_map_t map, mach_vm_offset_t* addr, mach
@@ -526,20 +561,218 @@ kern_return_t mach_vm_allocate_kernel(vm_map_t map, mach_vm_offset_t* addr, mach
}
};
@@ -570,8 +618,13 @@ index 3114947..e2a8d5e 100644
+ dtape_map_shared_descriptor_t* desc = NULL;
+ if (permission & MAP_MEM_NAMED_CREATE) {
+ memfd = memfd_create("darling-mementry", MFD_CLOEXEC);
+ if (memfd < 0 || ftruncate(memfd, map_size) < 0) {
+ if (memfd >= 0) close(memfd);
+ if (memfd < 0) {
+ dtape_diag_log_shortage("named-create memfd_create", memfd, map_size);
+ return KERN_RESOURCE_SHORTAGE;
+ }
+ if (ftruncate(memfd, map_size) < 0) {
+ dtape_diag_log_shortage("named-create ftruncate", memfd, map_size);
+ close(memfd);
+ return KERN_RESOURCE_SHORTAGE;
+ }
+ } else {
@@ -627,6 +680,7 @@ index 3114947..e2a8d5e 100644
+
+ desc = dtape_map_shared_descriptor_create(memfd, map_size);
+ if (desc == NULL) {
+ dtape_diag_log_shortage("named-entry descriptor malloc", memfd, map_size);
+ close(memfd);
+ return KERN_RESOURCE_SHORTAGE;
+ }
@@ -689,7 +743,7 @@ index 3114947..e2a8d5e 100644
};
kern_return_t mach_memory_info(host_priv_t host, mach_zone_name_array_t* namesp, mach_msg_type_number_t* namesCntp, mach_zone_info_array_t* infop, mach_msg_type_number_t* infoCntp, mach_memory_info_array_t* memoryInfop, mach_msg_type_number_t* memoryInfoCntp) {
@@ -591,8 +791,115 @@ kern_return_t mach_vm_machine_attribute(vm_map_t map, mach_vm_address_t addr, ma
@@ -591,8 +824,115 @@ kern_return_t mach_vm_machine_attribute(vm_map_t map, mach_vm_address_t addr, ma
};
kern_return_t mach_vm_map_external(vm_map_t target_map, mach_vm_offset_t* address, mach_vm_size_t initial_size, mach_vm_offset_t mask, int flags, ipc_port_t port, vm_object_offset_t offset, boolean_t copy, vm_prot_t cur_protection, vm_prot_t max_protection, vm_inherit_t inheritance) {
@@ -807,7 +861,7 @@ index 3114947..e2a8d5e 100644
};
kern_return_t mach_vm_msync(vm_map_t map, mach_vm_offset_t address, mach_vm_size_t size, vm_sync_t sync_flags) {
@@ -620,15 +927,22 @@ kern_return_t mach_vm_msync(vm_map_t map, mach_vm_offset_t address, mach_vm_size
@@ -620,15 +960,22 @@ kern_return_t mach_vm_msync(vm_map_t map, mach_vm_offset_t address, mach_vm_size
};
kern_return_t mach_vm_page_info(vm_map_t map, mach_vm_address_t address, vm_page_info_flavor_t flavor, vm_page_info_t info, mach_msg_type_number_t* count) {
@@ -833,7 +887,7 @@ index 3114947..e2a8d5e 100644
};
kern_return_t mach_vm_protect(vm_map_t map, mach_vm_offset_t start, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection) {
@@ -756,7 +1070,8 @@ region_info_out:
@@ -756,7 +1103,8 @@ region_info_out:
return kr;
};
default:
@@ -843,7 +897,7 @@ index 3114947..e2a8d5e 100644
}
};
@@ -856,7 +1171,7 @@ static kern_return_t mach_vm_remap_external_shared(vm_map_t target_map, mach_vm_
@@ -856,7 +1204,7 @@ static kern_return_t mach_vm_remap_external_shared(vm_map_t target_map, mach_vm_
src_existing_entry_count = dtape_map_find_shared_entries_locked(src_map, start_memaddr, map_size, src_existing_entries, sizeof(src_existing_entries) / sizeof(*src_existing_entries));
@@ -852,7 +906,7 @@ index 3114947..e2a8d5e 100644
// special case for what LLDB does with dyld info
dtape_map_shared_descriptor_retain(src_existing_entries[0]->descriptor);
descriptor = src_existing_entries[0]->descriptor;
@@ -1441,6 +1756,10 @@ mach_destroy_memory_entry(
@@ -1441,6 +1789,10 @@ mach_destroy_memory_entry(
named_entry->ref_count -= 1;
if (named_entry->ref_count == 0) {
@@ -863,7 +917,7 @@ index 3114947..e2a8d5e 100644
if (named_entry->is_sub_map) {
vm_map_deallocate(named_entry->backing.map);
} else if (named_entry->is_copy) {
@@ -1456,6 +1775,9 @@ mach_destroy_memory_entry(
@@ -1456,6 +1808,9 @@ mach_destroy_memory_entry(
named_entry_unlock(named_entry);
named_entry_lock_destroy(named_entry);
@@ -1802,7 +1856,7 @@ index cc10f1d..7df0056 100644
try {
thread->processSignal(_body.bsd_signal_number, _body.linux_signal_number, _body.code, _body.signal_address, _body.thread_state, _body.float_state);
diff --git a/src/darlingserver.cpp b/src/darlingserver.cpp
index f79f057..2bf9cfb 100644
index f79f057..54c42aa 100644
--- a/src/darlingserver.cpp
+++ b/src/darlingserver.cpp
@@ -497,6 +497,45 @@ static void handle_sigusr1(int signum) {
@@ -1882,7 +1936,25 @@ index f79f057..2bf9cfb 100644
if (argc < 6) {
fprintf(stderr, "darlingserver is not meant to be started manually\n");
exit(1);
@@ -745,6 +808,13 @@ int main(int argc, char** argv) {
@@ -577,8 +640,15 @@ int main(int argc, char** argv) {
// now set our increased rlimit
if (setrlimit(RLIMIT_NOFILE, &increased_limit) != 0) {
- fprintf(stderr, "Warning: failed to increase FD rlimit: %s\n", strerror(errno));
- //exit(1);
+ // darling-lol: a rootless user namespace cannot raise the hard limit.
+ // Still raise the soft limit to it: every named memory entry holds a
+ // memfd here, and Chromium's UX restart pushes past a 1024 soft limit,
+ // failing memfd_create with EMFILE.
+ increased_limit.rlim_cur = increased_limit.rlim_max = default_limit.rlim_max;
+ if (setrlimit(RLIMIT_NOFILE, &increased_limit) != 0) {
+ fprintf(stderr, "Warning: failed to increase FD rlimit: %s\n", strerror(errno));
+ //exit(1);
+ }
}
#endif
@@ -745,6 +815,13 @@ int main(int argc, char** argv) {
#endif
// create the server
+1 -1
View File
@@ -5051,7 +5051,7 @@ index b998456..c6281e6 100644
+ * (/tmp/rclol-local-semaphores, the former opt-in switch, is now a no-op). While it was on by default in every
+ * process (2026-10-10 22:22-23:50) LeagueClient died ~85 s after start in 3 of 4 checked launches
+ * ("mach_msg_overwrite failed -9", then dserver_rpc_interrupt_enter -9: its RPC descriptor had become invalid) and
+ * the user saw Vanguard errors; that mechanism is not understood, so the clients keep the server path. With the
+ * the client logged integrity-check errors; that mechanism is not understood, so the clients keep the server path. With the
+ * lifetime fixes above the game ran two full matches with it (2026-10-14: the main thread's server waits fell from
+ * 1.36 to 0.10 ms per frame, 39 to 15 blocks per frame). /tmp/rclol-local-semaphores-all turns it on for every
+ * process (probe tests). Decided once per process and logged
+1 -1
View File
@@ -10,5 +10,5 @@ OBJDUMP="$(command -v llvm-objdump || true)"
file "$BIN" | tee "$OUT/file.txt"
[ -n "$OTOOL" ] && { "$OTOOL" -hv "$BIN" > "$OUT/headers.txt" 2>&1; "$OTOOL" -L "$BIN" > "$OUT/linked-libs.txt" 2>&1; echo "wrote headers + linked-libs"; } || echo "no otool/llvm-otool found"
[ -n "$OBJDUMP" ] && "$OBJDUMP" --macho --dylibs-used "$BIN" > "$OUT/dylibs.txt" 2>&1 || true
strings -a "$BIN" | grep -iE "Metal|MTL|Vanguard|vgc|CEF|Chromium|RiotClient|NSApplication|LSOpen|CFBundle" | sort -u | head -100 | tee "$OUT/strings-of-interest.txt"
strings -a "$BIN" | { grep -iE "Metal|MTL|CEF|Chromium|RiotClient|NSApplication|LSOpen|CFBundle" || test "$?" -eq 1; } | sort -u | head -100 | tee "$OUT/strings-of-interest.txt"
echo "done -> $OUT/"