* Impersonating a process for file creation purposes @ 2015-04-16 9:28 Florian Weimer 2015-04-16 12:18 ` Stephen Smalley 2015-04-16 18:06 ` Daniel J Walsh 0 siblings, 2 replies; 10+ messages in thread From: Florian Weimer @ 2015-04-16 9:28 UTC (permalink / raw) To: SELinux List The ABRT coredump handler has code to emulate default core file creation (as if no such pipe-based handler was installed). The handler runs in a separate process, initially as root. Currently, the handler just switches effective IDs and creates the file. This does not replicate the SELinux context of the zombie process. Is there a way to do that? Is there some recommended way to inherit all the security-related process attributes? -- Florian Weimer / Red Hat Product Security ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Impersonating a process for file creation purposes 2015-04-16 9:28 Impersonating a process for file creation purposes Florian Weimer @ 2015-04-16 12:18 ` Stephen Smalley 2015-04-16 12:34 ` Florian Weimer 2015-04-27 9:06 ` Florian Weimer 2015-04-16 18:06 ` Daniel J Walsh 1 sibling, 2 replies; 10+ messages in thread From: Stephen Smalley @ 2015-04-16 12:18 UTC (permalink / raw) To: Florian Weimer, SELinux List On 04/16/2015 05:28 AM, Florian Weimer wrote: > The ABRT coredump handler has code to emulate default core file creation > (as if no such pipe-based handler was installed). The handler runs in a > separate process, initially as root. Currently, the handler just > switches effective IDs and creates the file. This does not replicate > the SELinux context of the zombie process. Pardon me for asking, but why does it include this code for emulating default core file creation, versus just letting the kernel directly handle it? > Is there a way to do that? Is there some recommended way to inherit > all the security-related process attributes? Technically it could use setcon() if allowed by policy but I wouldn't really recommend it. You'd have to allow it to dyntransition to any domain for any potential process you want it to be able to dump, at which point it could assume any of the permissions of any of those processes at will. Not so great if there is ever a vulnerability in ABRT itself. Plus any other process in the same context would be able to act on the handler at that point as they would then be in the same context. It could also compute the context in which the file would be created by the zombie by calling security_compute_create() with the context of the zombie process, the context of the directory into which it is writing the core dump file, and string_to_security_class("file") as its arguments, and then pass the resulting context returned by that call to setfscreatecon() prior to creating the core dump file and then call setfscreatecon(NULL) afterward; this will create the core dump file in that context. That seems more suited to your scenario. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Impersonating a process for file creation purposes 2015-04-16 12:18 ` Stephen Smalley @ 2015-04-16 12:34 ` Florian Weimer 2015-04-27 9:06 ` Florian Weimer 1 sibling, 0 replies; 10+ messages in thread From: Florian Weimer @ 2015-04-16 12:34 UTC (permalink / raw) To: Stephen Smalley, SELinux List On 04/16/2015 02:18 PM, Stephen Smalley wrote: > On 04/16/2015 05:28 AM, Florian Weimer wrote: >> The ABRT coredump handler has code to emulate default core file creation >> (as if no such pipe-based handler was installed). The handler runs in a >> separate process, initially as root. Currently, the handler just >> switches effective IDs and creates the file. This does not replicate >> the SELinux context of the zombie process. > > Pardon me for asking, but why does it include this code for emulating > default core file creation, versus just letting the kernel directly > handle it? It's either-or on the kernel side. You can spawn a process which is fed the core, or you can have the kernel write a core file. But not both at the same time. >> Is there a way to do that? Is there some recommended way to inherit >> all the security-related process attributes? > > Technically it could use setcon() if allowed by policy but I wouldn't > really recommend it. You'd have to allow it to dyntransition to any > domain for any potential process you want it to be able to dump, at > which point it could assume any of the permissions of any of those > processes at will. Not so great if there is ever a vulnerability in > ABRT itself. Plus any other process in the same context would be able > to act on the handler at that point as they would then be in the same > context. The handler would not be dumpable anymore because of the UID/GID transitions. But I do not need this level of impersonation. > It could also compute the context in which the file would be created by > the zombie by calling security_compute_create() with the context of the > zombie process, the context of the directory into which it is writing > the core dump file, and string_to_security_class("file") as its > arguments, and then pass the resulting context returned by that call to > setfscreatecon() prior to creating the core dump file and then call > setfscreatecon(NULL) afterward; this will create the core dump file in > that context. That seems more suited to your scenario. Right, that seems doable. I think I can even get the directory context without triggering new path name resolution. Thanks for the suggestion. -- Florian Weimer / Red Hat Product Security ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Impersonating a process for file creation purposes 2015-04-16 12:18 ` Stephen Smalley 2015-04-16 12:34 ` Florian Weimer @ 2015-04-27 9:06 ` Florian Weimer 2015-04-27 13:27 ` Stephen Smalley 1 sibling, 1 reply; 10+ messages in thread From: Florian Weimer @ 2015-04-27 9:06 UTC (permalink / raw) To: Stephen Smalley, SELinux List On 04/16/2015 02:18 PM, Stephen Smalley wrote: > It could also compute the context in which the file would be created by > the zombie by calling security_compute_create() with the context of the > zombie process, the context of the directory into which it is writing > the core dump file, and string_to_security_class("file") as its > arguments, and then pass the resulting context returned by that call to > setfscreatecon() prior to creating the core dump file and then call > setfscreatecon(NULL) afterward; this will create the core dump file in > that context. That seems more suited to your scenario. We tried this, and strace shows a lot of activity behind the scenes: 3449 open("/sys/fs/selinux/mls", O_RDONLY) = 4 3449 read(4, "1", 19) = 1 3449 close(4) = 0 3449 futex(0x7fefa9b34820, FUTEX_WAKE_PRIVATE, 2147483647) = 0 3449 socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 4 3449 connect(4, {sa_family=AF_LOCAL, sun_path="/var/run/setrans/.setrans-unix"}, 110) = -1 ENOENT (No such file or directory) 3449 close(4) = 0 3449 fgetxattr(3, "security.selinux", "unconfined_u:object_r:user_home_dir_t:s0", 255) = 41 3449 socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 4 3449 connect(4, {sa_family=AF_LOCAL, sun_path="/var/run/setrans/.setrans-unix"}, 110) = -1 ENOENT (No such file or directory) 3449 close(4) = 0 3449 stat("/sys/fs/selinux/class", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0 3449 futex(0x7fefa9b3375c, FUTEX_WAKE_PRIVATE, 2147483647) = 0 3449 open("/sys/fs/selinux/class/file/index", O_RDONLY) = 4 3449 read(4, "6", 19) = 1 3449 close(4) = 0 3449 openat(AT_FDCWD, "/sys/fs/selinux/class/file/perms", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 4 3449 getdents(4, /* 24 entries */, 32768) = 728 3449 open("/sys/fs/selinux/class/file/perms/.", O_RDONLY|O_CLOEXEC) = 5 3449 fstat(5, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0 3449 close(5) = 0 3449 open("/sys/fs/selinux/class/file/perms/..", O_RDONLY|O_CLOEXEC) = 5 3449 fstat(5, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0 3449 close(5) = 0 3449 open("/sys/fs/selinux/class/file/perms/audit_access", O_RDONLY|O_CLOEXEC) = 5 3449 fstat(5, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 3449 read(5, "22", 19) = 2 3449 close(5) = 0 3449 open("/sys/fs/selinux/class/file/perms/open", O_RDONLY|O_CLOEXEC) = 5 3449 fstat(5, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 3449 read(5, "21", 19) = 2 3449 close(5) = 0 And so on. We use this code sequence: if (getpidcon(pid, &srccon) < 0) { perror_msg("getpidcon(%d)", pid); return -1; } if (fgetfilecon(dirfd(proc_cwd), &dstcon) < 0) { perror_msg("getfilecon(%s)", user_pwd); return -1; } if (security_compute_create(srccon, dstcon, string_to_security_class("file"), &newcon) < 0) { perror_msg("security_compute_create()"); return -1; } if (setfscreatecon(newcon) < 0) { perror_msg("setfscreatecon(newcon)"); return -1; } This happens after switching to the other user ID (not root), and I think we should run the preparatory steps (everything before the call to setfscreatecon) as root. Is there are supported way to get something leaner? Is it really necessary to get setrans involved? Can't we just copy the kernel context without translating it back and forth? -- Florian Weimer / Red Hat Product Security ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Impersonating a process for file creation purposes 2015-04-27 9:06 ` Florian Weimer @ 2015-04-27 13:27 ` Stephen Smalley 2015-04-27 14:20 ` Stephen Smalley 0 siblings, 1 reply; 10+ messages in thread From: Stephen Smalley @ 2015-04-27 13:27 UTC (permalink / raw) To: Florian Weimer, SELinux List On 04/27/2015 05:06 AM, Florian Weimer wrote: > On 04/16/2015 02:18 PM, Stephen Smalley wrote: > >> It could also compute the context in which the file would be created by >> the zombie by calling security_compute_create() with the context of the >> zombie process, the context of the directory into which it is writing >> the core dump file, and string_to_security_class("file") as its >> arguments, and then pass the resulting context returned by that call to >> setfscreatecon() prior to creating the core dump file and then call >> setfscreatecon(NULL) afterward; this will create the core dump file in >> that context. That seems more suited to your scenario. > > We tried this, and strace shows a lot of activity behind the scenes: > > 3449 open("/sys/fs/selinux/mls", O_RDONLY) = 4 > 3449 read(4, "1", 19) = 1 > 3449 close(4) = 0 > 3449 futex(0x7fefa9b34820, FUTEX_WAKE_PRIVATE, 2147483647) = 0 > 3449 socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 4 > 3449 connect(4, {sa_family=AF_LOCAL, > sun_path="/var/run/setrans/.setrans-unix"}, 110) = -1 ENOENT (No such > file or directory) > 3449 close(4) = 0 > 3449 fgetxattr(3, "security.selinux", > "unconfined_u:object_r:user_home_dir_t:s0", 255) = 41 > 3449 socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 4 > 3449 connect(4, {sa_family=AF_LOCAL, > sun_path="/var/run/setrans/.setrans-unix"}, 110) = -1 ENOENT (No such > file or directory) > 3449 close(4) = 0 > 3449 stat("/sys/fs/selinux/class", {st_mode=S_IFDIR|0555, st_size=0, > ...}) = 0 > 3449 futex(0x7fefa9b3375c, FUTEX_WAKE_PRIVATE, 2147483647) = 0 > 3449 open("/sys/fs/selinux/class/file/index", O_RDONLY) = 4 > 3449 read(4, "6", 19) = 1 > 3449 close(4) = 0 > 3449 openat(AT_FDCWD, "/sys/fs/selinux/class/file/perms", > O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 4 > 3449 getdents(4, /* 24 entries */, 32768) = 728 > 3449 open("/sys/fs/selinux/class/file/perms/.", O_RDONLY|O_CLOEXEC) = 5 > 3449 fstat(5, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0 > 3449 close(5) = 0 > 3449 open("/sys/fs/selinux/class/file/perms/..", O_RDONLY|O_CLOEXEC) = 5 > 3449 fstat(5, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0 > 3449 close(5) = 0 > 3449 open("/sys/fs/selinux/class/file/perms/audit_access", > O_RDONLY|O_CLOEXEC) = 5 > 3449 fstat(5, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 > 3449 read(5, "22", 19) = 2 > 3449 close(5) = 0 > 3449 open("/sys/fs/selinux/class/file/perms/open", O_RDONLY|O_CLOEXEC) = 5 > 3449 fstat(5, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 > 3449 read(5, "21", 19) = 2 > 3449 close(5) = 0 > > And so on. > > We use this code sequence: > > if (getpidcon(pid, &srccon) < 0) > { > perror_msg("getpidcon(%d)", pid); > return -1; > } > > if (fgetfilecon(dirfd(proc_cwd), &dstcon) < 0) > { > perror_msg("getfilecon(%s)", user_pwd); > return -1; > } > > if (security_compute_create(srccon, dstcon, > string_to_security_class("file"), &newcon) < 0) > { > perror_msg("security_compute_create()"); > return -1; > } > > if (setfscreatecon(newcon) < 0) > { > perror_msg("setfscreatecon(newcon)"); > return -1; > } > > This happens after switching to the other user ID (not root), and I > think we should run the preparatory steps (everything before the call to > setfscreatecon) as root. > > Is there are supported way to get something leaner? Is it really > necessary to get setrans involved? Can't we just copy the kernel > context without translating it back and forth? You can use the _raw interfaces to avoid the context translation. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Impersonating a process for file creation purposes 2015-04-27 13:27 ` Stephen Smalley @ 2015-04-27 14:20 ` Stephen Smalley 0 siblings, 0 replies; 10+ messages in thread From: Stephen Smalley @ 2015-04-27 14:20 UTC (permalink / raw) To: Florian Weimer, SELinux List On 04/27/2015 09:27 AM, Stephen Smalley wrote: > On 04/27/2015 05:06 AM, Florian Weimer wrote: >> On 04/16/2015 02:18 PM, Stephen Smalley wrote: >> >>> It could also compute the context in which the file would be created by >>> the zombie by calling security_compute_create() with the context of the >>> zombie process, the context of the directory into which it is writing >>> the core dump file, and string_to_security_class("file") as its >>> arguments, and then pass the resulting context returned by that call to >>> setfscreatecon() prior to creating the core dump file and then call >>> setfscreatecon(NULL) afterward; this will create the core dump file in >>> that context. That seems more suited to your scenario. >> >> We tried this, and strace shows a lot of activity behind the scenes: >> >> 3449 open("/sys/fs/selinux/mls", O_RDONLY) = 4 >> 3449 read(4, "1", 19) = 1 >> 3449 close(4) = 0 >> 3449 futex(0x7fefa9b34820, FUTEX_WAKE_PRIVATE, 2147483647) = 0 >> 3449 socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 4 >> 3449 connect(4, {sa_family=AF_LOCAL, >> sun_path="/var/run/setrans/.setrans-unix"}, 110) = -1 ENOENT (No such >> file or directory) >> 3449 close(4) = 0 >> 3449 fgetxattr(3, "security.selinux", >> "unconfined_u:object_r:user_home_dir_t:s0", 255) = 41 >> 3449 socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 4 >> 3449 connect(4, {sa_family=AF_LOCAL, >> sun_path="/var/run/setrans/.setrans-unix"}, 110) = -1 ENOENT (No such >> file or directory) >> 3449 close(4) = 0 >> 3449 stat("/sys/fs/selinux/class", {st_mode=S_IFDIR|0555, st_size=0, >> ...}) = 0 >> 3449 futex(0x7fefa9b3375c, FUTEX_WAKE_PRIVATE, 2147483647) = 0 >> 3449 open("/sys/fs/selinux/class/file/index", O_RDONLY) = 4 >> 3449 read(4, "6", 19) = 1 >> 3449 close(4) = 0 >> 3449 openat(AT_FDCWD, "/sys/fs/selinux/class/file/perms", >> O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 4 >> 3449 getdents(4, /* 24 entries */, 32768) = 728 >> 3449 open("/sys/fs/selinux/class/file/perms/.", O_RDONLY|O_CLOEXEC) = 5 >> 3449 fstat(5, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0 >> 3449 close(5) = 0 >> 3449 open("/sys/fs/selinux/class/file/perms/..", O_RDONLY|O_CLOEXEC) = 5 >> 3449 fstat(5, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0 >> 3449 close(5) = 0 >> 3449 open("/sys/fs/selinux/class/file/perms/audit_access", >> O_RDONLY|O_CLOEXEC) = 5 >> 3449 fstat(5, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 >> 3449 read(5, "22", 19) = 2 >> 3449 close(5) = 0 >> 3449 open("/sys/fs/selinux/class/file/perms/open", O_RDONLY|O_CLOEXEC) = 5 >> 3449 fstat(5, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 >> 3449 read(5, "21", 19) = 2 >> 3449 close(5) = 0 >> >> And so on. >> >> We use this code sequence: >> >> if (getpidcon(pid, &srccon) < 0) >> { >> perror_msg("getpidcon(%d)", pid); >> return -1; >> } >> >> if (fgetfilecon(dirfd(proc_cwd), &dstcon) < 0) >> { >> perror_msg("getfilecon(%s)", user_pwd); >> return -1; >> } >> >> if (security_compute_create(srccon, dstcon, >> string_to_security_class("file"), &newcon) < 0) >> { >> perror_msg("security_compute_create()"); >> return -1; >> } >> >> if (setfscreatecon(newcon) < 0) >> { >> perror_msg("setfscreatecon(newcon)"); >> return -1; >> } >> >> This happens after switching to the other user ID (not root), and I >> think we should run the preparatory steps (everything before the call to >> setfscreatecon) as root. >> >> Is there are supported way to get something leaner? Is it really >> necessary to get setrans involved? Can't we just copy the kernel >> context without translating it back and forth? > > You can use the _raw interfaces to avoid the context translation. Also, the reading of the /sys/fs/selinux/class tree should be done once and then cached by libselinux, so you shouldn't see that each time. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Impersonating a process for file creation purposes 2015-04-16 9:28 Impersonating a process for file creation purposes Florian Weimer 2015-04-16 12:18 ` Stephen Smalley @ 2015-04-16 18:06 ` Daniel J Walsh 2015-04-20 14:05 ` Florian Weimer 1 sibling, 1 reply; 10+ messages in thread From: Daniel J Walsh @ 2015-04-16 18:06 UTC (permalink / raw) To: Florian Weimer, SELinux List On 04/16/2015 05:28 AM, Florian Weimer wrote: > The ABRT coredump handler has code to emulate default core file creation > (as if no such pipe-based handler was installed). The handler runs in a > separate process, initially as root. Currently, the handler just > switches effective IDs and creates the file. This does not replicate > the SELinux context of the zombie process. > > Is there a way to do that? Is there some recommended way to inherit > all the security-related process attributes? > You have two choices. 1 would be to setcon() call to change the label to the user process. The other choice would be to ask the kernel what label this user would create if he created a file in the specified directory. This is what systemd does. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Impersonating a process for file creation purposes 2015-04-16 18:06 ` Daniel J Walsh @ 2015-04-20 14:05 ` Florian Weimer 2015-04-28 17:12 ` Miroslav Grepl 0 siblings, 1 reply; 10+ messages in thread From: Florian Weimer @ 2015-04-20 14:05 UTC (permalink / raw) To: Daniel J Walsh, SELinux List On 04/16/2015 08:06 PM, Daniel J Walsh wrote: > > On 04/16/2015 05:28 AM, Florian Weimer wrote: >> The ABRT coredump handler has code to emulate default core file creation >> (as if no such pipe-based handler was installed). The handler runs in a >> separate process, initially as root. Currently, the handler just >> switches effective IDs and creates the file. This does not replicate >> the SELinux context of the zombie process. >> >> Is there a way to do that? Is there some recommended way to inherit >> all the security-related process attributes? >> > You have two choices. 1 would be to setcon() call to change the label > to the user process. > > The other choice would be to ask the kernel what label this user would > create if he created a file > in the specified directory. This is what systemd does. Dan, could you please double-check if this change (implementing the second option) looks reasonable? <https://github.com/abrt/abrt/commit/3e4155bfcd9f6f5a20964080fa05724503b20761> Thanks, Florian -- Florian Weimer / Red Hat Product Security ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Impersonating a process for file creation purposes 2015-04-20 14:05 ` Florian Weimer @ 2015-04-28 17:12 ` Miroslav Grepl 2015-04-28 17:19 ` Florian Weimer 0 siblings, 1 reply; 10+ messages in thread From: Miroslav Grepl @ 2015-04-28 17:12 UTC (permalink / raw) To: Florian Weimer, Daniel J Walsh, SELinux List On 04/20/2015 04:05 PM, Florian Weimer wrote: > On 04/16/2015 08:06 PM, Daniel J Walsh wrote: >> >> On 04/16/2015 05:28 AM, Florian Weimer wrote: >>> The ABRT coredump handler has code to emulate default core file creation >>> (as if no such pipe-based handler was installed). The handler runs in a >>> separate process, initially as root. Currently, the handler just >>> switches effective IDs and creates the file. This does not replicate >>> the SELinux context of the zombie process. >>> >>> Is there a way to do that? Is there some recommended way to inherit >>> all the security-related process attributes? >>> >> You have two choices. 1 would be to setcon() call to change the label >> to the user process. >> >> The other choice would be to ask the kernel what label this user would >> create if he created a file >> in the specified directory. This is what systemd does. > > Dan, could you please double-check if this change (implementing the > second option) looks reasonable? > > <https://github.com/abrt/abrt/commit/3e4155bfcd9f6f5a20964080fa05724503b20761> I would go with _raw interfaces how Stephen suggested above. Also we should take care about ABRT SELinux policy. > Thanks, > Florian > -- Miroslav Grepl Software Engineering, SELinux Solutions Red Hat, Inc. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Impersonating a process for file creation purposes 2015-04-28 17:12 ` Miroslav Grepl @ 2015-04-28 17:19 ` Florian Weimer 0 siblings, 0 replies; 10+ messages in thread From: Florian Weimer @ 2015-04-28 17:19 UTC (permalink / raw) To: Miroslav Grepl, Daniel J Walsh, SELinux List On 04/28/2015 07:12 PM, Miroslav Grepl wrote: >> <https://github.com/abrt/abrt/commit/3e4155bfcd9f6f5a20964080fa05724503b20761> > > I would go with _raw interfaces how Stephen suggested above. Thanks. I think the current version is here: <https://github.com/abrt/abrt/commit/c4f06d4198658c82550e93bb2617b96022c06cf4> > Also we should take care about ABRT SELinux policy. See <https://bugzilla.redhat.com/show_bug.cgi?id=1212885>. As far as I understand it, with the current default behavior, an effective SELinux policy is difficult to write. -- Florian Weimer / Red Hat Product Security ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2015-04-28 17:19 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-04-16 9:28 Impersonating a process for file creation purposes Florian Weimer 2015-04-16 12:18 ` Stephen Smalley 2015-04-16 12:34 ` Florian Weimer 2015-04-27 9:06 ` Florian Weimer 2015-04-27 13:27 ` Stephen Smalley 2015-04-27 14:20 ` Stephen Smalley 2015-04-16 18:06 ` Daniel J Walsh 2015-04-20 14:05 ` Florian Weimer 2015-04-28 17:12 ` Miroslav Grepl 2015-04-28 17:19 ` Florian Weimer
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.