All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] Cascade: a high level SELinux policy language
@ 2021-11-04 18:13 Daniel Burgener
  2021-11-05 19:19 ` James Carter
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel Burgener @ 2021-11-04 18:13 UTC (permalink / raw)
  To: selinux, Mickaël Salaün, James Morris, Paul Moore,
	Chris PeBenito

We have been working over the past few months on a new high level 
language for specifying SELinux policy, in line with the original intent 
of CIL, to enable the creation of high level languages that compile into 
CIL.

Our objective is to create a language that enables the efficient 
creation of useful abstractions by policy experts while enabling those 
abstractions to be easily usable by non-experts who may contribute to 
portions of the policy.

The design is heavily influenced by Object Oriented principles, with a 
goal of enabling the efficient creation of type hierarchies and 
eliminating boilerplate through the use of inheritance.  The use of 
"virtual" types, (which compile into attributes) allows both attribute 
like behavior, and also the creation of inherited member functions, 
allowing for interfaces as in refpolicy without the redundant 
boilerplate.  Another key feature is "resource association" which makes 
explicit the connections between domains and associated types such as 
tmp files.  This feature allows for common patterns (such as setting up 
a tmp file with a domain transition rule and manage access) to be done 
automatically behind the scenes, minimizing the chance of mistakes and 
allowing policy developers to focus more on security decisions.

The core language functionality is written as a library, which will 
hopefully enable the easy creation of associated tooling and plugins 
that build on top of that library.  It is our hope that this 
architecture will assist an expansion of available tooling to aid policy 
developers in their work.

This is still a very early prototype and so some functionality may be 
missing or incomplete, but we wanted to make what we have so far 
available for community feedback and discussion as we continue development.

You can find the code and associated documentation at 
https://github.com/dburgener/cascade

I hope this is something that people will find useful and welcome 
feedback and contributions as we aim towards the goal of enabling 
smoother policy development.

-Daniel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC] Cascade: a high level SELinux policy language
  2021-11-04 18:13 [RFC] Cascade: a high level SELinux policy language Daniel Burgener
@ 2021-11-05 19:19 ` James Carter
  2021-11-08 20:43   ` Daniel Burgener
  0 siblings, 1 reply; 5+ messages in thread
From: James Carter @ 2021-11-05 19:19 UTC (permalink / raw)
  To: Daniel Burgener
  Cc: SElinux list, Mickaël Salaün, James Morris, Paul Moore,
	Chris PeBenito

On Thu, Nov 4, 2021 at 2:14 PM Daniel Burgener
<dburgener@linux.microsoft.com> wrote:
>
> We have been working over the past few months on a new high level
> language for specifying SELinux policy, in line with the original intent
> of CIL, to enable the creation of high level languages that compile into
> CIL.
>

If you ever feel like CIL doesn't quite do what you need or that it
doesn't work as expected, please let me know.

> Our objective is to create a language that enables the efficient
> creation of useful abstractions by policy experts while enabling those
> abstractions to be easily usable by non-experts who may contribute to
> portions of the policy.
>
> The design is heavily influenced by Object Oriented principles, with a
> goal of enabling the efficient creation of type hierarchies and
> eliminating boilerplate through the use of inheritance.  The use of
> "virtual" types, (which compile into attributes) allows both attribute
> like behavior, and also the creation of inherited member functions,
> allowing for interfaces as in refpolicy without the redundant
> boilerplate.  Another key feature is "resource association" which makes
> explicit the connections between domains and associated types such as
> tmp files.  This feature allows for common patterns (such as setting up
> a tmp file with a domain transition rule and manage access) to be done
> automatically behind the scenes, minimizing the chance of mistakes and
> allowing policy developers to focus more on security decisions.
>

I realize that many of my questions below will be answered with
"future work", so don't feel like you need to explain in great detail
if that is the case.

How different is the inheritance in Cascade as compared to CIL.
Obviously, in CIL it is not required, where in Cascade it is a very
important part. There is also the use of "this" in Cascade.

It seems like Cascade is resolving all of its inheritance before
writing out the CIL. My guess is that inheritance is such a core part
of Cascade that using CIL's inheritance would make no sense. Is that
true? Or did you just not like the way CIL does it?

I was surprised that casc only take a single file. Do you expect the
policies to be simple enough to do in one file?

Since there is only one file, I guess there is no concept of modules
for Cascade? And this means there is no need for something like an
optional block because all of the policy would be compiled at once?

It looks like classes, mls statements, and sids are all automatically
created in CIL. Is there a way to specify these things in Cascade or,
since these things are almost always the same, are these low-level
details something Cascade is not worried about.

What about roles and users. I see the keywords, but how are they going to work?

Thanks for letting us know about this work. It looks interesting.
Jim



> The core language functionality is written as a library, which will
> hopefully enable the easy creation of associated tooling and plugins
> that build on top of that library.  It is our hope that this
> architecture will assist an expansion of available tooling to aid policy
> developers in their work.
>
> This is still a very early prototype and so some functionality may be
> missing or incomplete, but we wanted to make what we have so far
> available for community feedback and discussion as we continue development.
>
> You can find the code and associated documentation at
> https://github.com/dburgener/cascade
>
> I hope this is something that people will find useful and welcome
> feedback and contributions as we aim towards the goal of enabling
> smoother policy development.
>
> -Daniel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC] Cascade: a high level SELinux policy language
  2021-11-05 19:19 ` James Carter
@ 2021-11-08 20:43   ` Daniel Burgener
       [not found]     ` <CA+EEuAhzFYQhLMXKgAOy_bzhdJV3a0Rqp9YSSot16+e32Vhv6Q@mail.gmail.com>
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel Burgener @ 2021-11-08 20:43 UTC (permalink / raw)
  To: James Carter
  Cc: SElinux list, Mickaël Salaün, James Morris, Paul Moore,
	Chris PeBenito

On 11/5/2021 3:19 PM, James Carter wrote:
> On Thu, Nov 4, 2021 at 2:14 PM Daniel Burgener
> <dburgener@linux.microsoft.com> wrote:
>>
>> We have been working over the past few months on a new high level
>> language for specifying SELinux policy, in line with the original intent
>> of CIL, to enable the creation of high level languages that compile into
>> CIL.
>>
> 
> If you ever feel like CIL doesn't quite do what you need or that it
> doesn't work as expected, please let me know.

Absolutely.  So far, CIL has worked great for what I need.  I'll 
definitely contribute or reach out if I run into issues though.  I 
hope/expect that the overall development will exercise some CIL corner 
cases that may not have gotten a lot of use in the past, although that 
remains to be seen.

> 
>> Our objective is to create a language that enables the efficient
>> creation of useful abstractions by policy experts while enabling those
>> abstractions to be easily usable by non-experts who may contribute to
>> portions of the policy.
>>
>> The design is heavily influenced by Object Oriented principles, with a
>> goal of enabling the efficient creation of type hierarchies and
>> eliminating boilerplate through the use of inheritance.  The use of
>> "virtual" types, (which compile into attributes) allows both attribute
>> like behavior, and also the creation of inherited member functions,
>> allowing for interfaces as in refpolicy without the redundant
>> boilerplate.  Another key feature is "resource association" which makes
>> explicit the connections between domains and associated types such as
>> tmp files.  This feature allows for common patterns (such as setting up
>> a tmp file with a domain transition rule and manage access) to be done
>> automatically behind the scenes, minimizing the chance of mistakes and
>> allowing policy developers to focus more on security decisions.
>>
> 
> I realize that many of my questions below will be answered with
> "future work", so don't feel like you need to explain in great detail
> if that is the case.
> 
> How different is the inheritance in Cascade as compared to CIL.
> Obviously, in CIL it is not required, where in Cascade it is a very
> important part. There is also the use of "this" in Cascade.

I definitely have less CIL expertise than you, so please correct me if I 
have anything inaccurate about CIL.  I don't think there are any 
fundamental differences/incompatibilities between CIL inheritance and 
Cascade inheritance, at least not in the big picture.  They're both 
generally aiming at solving a similar problem in a similar manner.  They 
both inherit rules and create name mangled derived types for children. 
In contrast to CIL, Cascade intermingles attributes and inheritance.  So 
if I inherit from a parent, I automatically have an attribute for all 
children that I can reference elsewhere.  Cascade inheritance is also 
used to check function arguments.  So I can have a function that only 
takes children of the foo type and will throw a compiler error if used 
otherwise.  I don't *think* CIL has something similar to that?

I think one of the bigger distinctions (across the board, but including 
inheritance) is that syntactic sugar is an explicit non-goal of CIL, and 
an explicit goal of Cascade. Our objective is to make inheritance easier 
to use and natural feeling for developers who are familiar with object 
oriented programming languages.  I'll leave it up to others to decide 
whether we've succeeded there, and/or whether we can succeed there as we 
continue to develop.

> 
> It seems like Cascade is resolving all of its inheritance before
> writing out the CIL. My guess is that inheritance is such a core part
> of Cascade that using CIL's inheritance would make no sense. Is that
> true? Or did you just not like the way CIL does it?

This was mostly just around the centrality of the inheritance feature to 
Cascade.  It seemed like we'd have more flexibility doing that one by 
hand so to speak.  Our overall goal was to avoid reimplementing things 
that CIL already does, and just compile into the underlying CIL feature. 
  It's entirely possible that we could have/could in the future make 
more use of CIL's inheritance functionality.  That would be a win in 
terms of interoperability.  Inheritance of non-virtual types is on my 
TODO list, and when I get to that, I'll do some more in depth digging on 
whether we can lean more into existing CIL functionality here, which 
might make that use case easier.  That said, doing name mangling in our 
code rather than leaving it to CIL allows us the ability to have more 
control over applying things like annotations.  Annotations aren't used 
yet to their full potential, but my hope is that they can ultimately be 
used to provide a set of "debug symbols" consumed by audit2cascade and 
other tooling, in order to improve automated response to detected AVC 
denials, and policy discoverability for non-experts trying to understand 
said denials.  I *think* that as we aim to continue down that path, 
having full control over the list of types in the policy from inside the 
Cascade compiler will be important.

> 
> I was surprised that casc only take a single file. Do you expect the
> policies to be simple enough to do in one file?

Future work.  The library backend supports it, but I haven't updated the 
front end yet.

> 
> Since there is only one file, I guess there is no concept of modules
> for Cascade? And this means there is no need for something like an
> optional block because all of the policy would be compiled at once?

Future work.  Our primary internal use case that we hope to migrate for 
Cascade for involves compiling policies for multiple systems from the 
same repo, so we'll definitely need module support.  In particular the 
ability to mix and match groups of modules easily is important to us. 
What I'd like to do is add new `system {}` and `module {}` blocks that 
integrate naturally with everything else, and add options to casc to 
support easily building multiple systems.  On our existing refpolicy 
based setup, we have to do a lot of shell script processing to get 
everything to work well, and it's challenging to maintain.

In terms of optional blocks, Chris and I have argued about optional a 
few times, and part of the reason there's nothing about optional so far 
is because we'd like to solicit community feedback there.  My personal 
view is that explicitly marking statements as optional is tedious and 
error prone.  But I don't have a really slam dunk "clearly better" 
solution to propose yet at this point.  I have a few ideas, but they all 
need to be more thoroughly thought out and there are some holes and 
issues to address.  I viewed this feature as non-essential for an 
initial proof of concept, and am glad that we can have design 
discussions about it in the open.

So in short, yes, I think the ability to differentiate that certain 
rules are required for a module to work and others are optional is 
definitely needed.  But I'm not yet set on what the best way to do that 
is.  One key goal here is that a developer of a component should be able 
to add policy with fairly minimal knowledge of SELinux.  I'd prefer it 
if most of the time they could do the right thing without knowing about 
optional, but I'm not yet sure what the best/cleanest way to achieve 
that will be.

> 
> It looks like classes, mls statements, and sids are all automatically
> created in CIL. Is there a way to specify these things in Cascade or,
> since these things are almost always the same, are these low-level
> details something Cascade is not worried about.

Yes, currently these things are all hard-coded in CIL.  My goal in 
general is to have sensible defaults for people who don't care, but 
allow override for people who do.  So where I'd like to get to in the 
long term is to continue to define these things in code, but allow 
policy developers or either modify the defaults, or completely override 
them with their own implementations.  That's future work.

> 
> What about roles and users. I see the keywords, but how are they going to work?

Future work.  The overall goal would be for users who say "I don't need 
UBAC" or "I don't need RBAC", then they could just get something with 
automatic users and roles, like as in Android, with zero effort.  But we 
definitely want fully featured UBAC and RBAC support available for those 
who need it.

> 
> Thanks for letting us know about this work. It looks interesting.
> Jim

Thanks!  Thanks for your feedback/questions.

> 
> 
> 
>> The core language functionality is written as a library, which will
>> hopefully enable the easy creation of associated tooling and plugins
>> that build on top of that library.  It is our hope that this
>> architecture will assist an expansion of available tooling to aid policy
>> developers in their work.
>>
>> This is still a very early prototype and so some functionality may be
>> missing or incomplete, but we wanted to make what we have so far
>> available for community feedback and discussion as we continue development.
>>
>> You can find the code and associated documentation at
>> https://github.com/dburgener/cascade
>>
>> I hope this is something that people will find useful and welcome
>> feedback and contributions as we aim towards the goal of enabling
>> smoother policy development.
>>
>> -Daniel


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC] Cascade: a high level SELinux policy language
       [not found]     ` <CA+EEuAhzFYQhLMXKgAOy_bzhdJV3a0Rqp9YSSot16+e32Vhv6Q@mail.gmail.com>
@ 2021-11-09 18:16       ` Daniel Burgener
  2021-11-09 18:39         ` James Carter
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel Burgener @ 2021-11-09 18:16 UTC (permalink / raw)
  To: Karl MacMillan
  Cc: James Carter, SElinux list, Mickaël Salaün,
	James Morris, Paul Moore, Chris PeBenito

On 11/9/2021 11:03 AM, Karl MacMillan wrote:
> Daniel,
> 
> I'll just say - thanks for including me. It's interesting to see your 
> work. I've got some comments below inline.
> 
> On Mon, Nov 8, 2021 at 3:43 PM Daniel Burgener 
> <dburgener@linux.microsoft.com <mailto:dburgener@linux.microsoft.com>> 
> wrote:
> 
> 
>     I definitely have less CIL expertise than you, so please correct me
>     if I
>     have anything inaccurate about CIL.  I don't think there are any
>     fundamental differences/incompatibilities between CIL inheritance and
>     Cascade inheritance, at least not in the big picture.  They're both
>     generally aiming at solving a similar problem in a similar manner. 
>     They
>     both inherit rules and create name mangled derived types for children.
>     In contrast to CIL, Cascade intermingles attributes and
>     inheritance.  So
>     if I inherit from a parent, I automatically have an attribute for all
>     children that I can reference elsewhere. 
> 
> 
> That's certainly interesting and I see the appeal. I'll be curious to 
> see how that works out long term. I think one of the reasons that CIL 
> inheritance was separate from that originally was because attributes are 
> not great at expressing access access within a set of types that is 
> private vs they should all have interrelated access. I apologize for not 
> having looked at your proposed language closely enough to know the 
> semantics in detail (I read through the documentation, but was not able 
> to understand how some cases would work).
> 
> For example, let's say you have a "base class" for all services that can 
> be started by init, can write to the logging facilities (syslog / 
> journal), and have a pid file. The challenge that I see in that case is 
> that upon inheritance, the children sometimes get access to the 
> resources of the parents (i.e., init can exec them and they can still 
> write to syslog / journal), but sometimes they get _copies_ of the 
> resources with distinct access that is separated in the children (the 
> pid files).
> 
> That's hard to express with attributes and I think it's different from 
> normal object-oriented programming in some ways. Maybe you can express 
> it with static members vs instance members, but then it feels like you 
> need to "instantiate" the types vs this declarative language?

I agree that this is a challenge.  I *think* our model handles it 
cleanly, although we haven't had the "stress test" that implementing a 
full system policy in it will undoubtedly provide and I'd be surprised 
if we don't come across some interesting scenarios we haven't given 
enough thought to.

A lot of this is handled with the @associate annotation which allows for 
automatic deriving and access of the child.  In your example, I would do 
something like:

virtual resource init_pid {
	@associated_call
	fn use_init_pid(domain source) {
		this.manage(source);
	}
}

@associate([init_pid])
virtual domain init_daemon_domain {
	syslog.write(); // defined elsewhere
}

domain my_service inherits init_daemon {}

The key thing here with respect to what we're discussing is that when we 
inherit from init_daemon_domain we get a *copy* of all of 
init_daemon_domain's associated resources, and the @associated_call hook 
is called for each child on the copy.  So in this situation, my_service 
would inherit the syslog permissions (and the init domain elsewhere 
could reference all init_daemon_domains), but in terms of the policy 
that becomes unique to each child, that is defined in the 
@associated_call annotated function (and there can be multiple such 
functions if you desire), and it's called under the hood for all the 
children.

This conversation has also reminded me that we intended to have an 
@noinherit annotation for things that wouldn't be passed on to the 
children.  For example, there may be scenarios where it's beneficial to 
have init_daemon_domain associate with a resource and have the children 
*not* get copies of such a resource.  That particular feature got lost 
in the shuffle, so I may need to loop back on it.

Even without that though, I think the association mechanism here hits 
the key points on this challenge, and covers at least the common cases 
pretty cleanly.  Let me know if you think something is missing here.

> 
> Maybe you handle all of this?
> 
> 
>     In terms of optional blocks, Chris and I have argued about optional a
>     few times, and part of the reason there's nothing about optional so far
>     is because we'd like to solicit community feedback there.  My personal
>     view is that explicitly marking statements as optional is tedious and
>     error prone.  But I don't have a really slam dunk "clearly better"
>     solution to propose yet at this point.  I have a few ideas, but they
>     all
>     need to be more thoroughly thought out and there are some holes and
>     issues to address.  I viewed this feature as non-essential for an
>     initial proof of concept, and am glad that we can have design
>     discussions about it in the open.
> 
>     So in short, yes, I think the ability to differentiate that certain
>     rules are required for a module to work and others are optional is
>     definitely needed.  But I'm not yet set on what the best way to do that
>     is.  One key goal here is that a developer of a component should be
>     able
>     to add policy with fairly minimal knowledge of SELinux.  I'd prefer it
>     if most of the time they could do the right thing without knowing about
>     optional, but I'm not yet sure what the best/cleanest way to achieve
>     that will be.
> 
> 
> Optional blocks have, in practice, been a huge source of errors I 
> believe.
 > [snip]

I agree pretty much 100% with everything you've said here about the 
usage and historical limitations of optional.  Thanks for the added 
historical context from before my time.

On the topic of packaging, I'll admit that I'm sparse on details without 
an actual implementation at this point, so the packaging aspect of 
Cascade is currently vaporware, but my hope is that an integrated 
packaging and build system framework, inspired by rust's cargo can solve 
a lot of the packaging problems much more cleanly (by inserting optional 
blocks for install order problems during compilation rather than in 
source for example).

I like the suggestion of a question mark operator for optional policy 
quite a bit.  Although I'm really interested in exploring whether it's 
possible to just treat the entirety of it as a policy level dependency 
resolution problem.  Basically annotate with modules a particular module 
depends on vs which are optional - the distinction being that the 
optional marking is done at the module level rather than the 
rule/interface call level.  That might be less heavy-weight and error 
prone to use while still providing the needed flexibility.

> Anyway - forgive me crashing in with all of my opinions. I hope my 
> background on the problems of optionals might at least be helpful.

Opinions are what I'm seeking. :)  And yes, I think all of your thoughts 
here are quite helpful.  I think the attributes concern is a good one 
that we aimed to address, and can continue to refine as needed, and the 
optional thoughts are extremely helpful, since as I mentioned in my 
prior e-mail, the overall support for differentiating which policy is 
required and which is optional is a must-have in my view, but how 
exactly to specify it in a way that is clear is somewhat challenging and 
subjective.  Added info on historical context and use cases is a 
valuable input to that discussion.

-Daniel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC] Cascade: a high level SELinux policy language
  2021-11-09 18:16       ` Daniel Burgener
@ 2021-11-09 18:39         ` James Carter
  0 siblings, 0 replies; 5+ messages in thread
From: James Carter @ 2021-11-09 18:39 UTC (permalink / raw)
  To: Daniel Burgener
  Cc: Karl MacMillan, SElinux list, Mickaël Salaün,
	James Morris, Paul Moore, Chris PeBenito

On Tue, Nov 9, 2021 at 1:16 PM Daniel Burgener
<dburgener@linux.microsoft.com> wrote:
>
> On 11/9/2021 11:03 AM, Karl MacMillan wrote:
> > Daniel,

> >
> >
> >     In terms of optional blocks, Chris and I have argued about optional a
> >     few times, and part of the reason there's nothing about optional so far
> >     is because we'd like to solicit community feedback there.  My personal
> >     view is that explicitly marking statements as optional is tedious and
> >     error prone.  But I don't have a really slam dunk "clearly better"
> >     solution to propose yet at this point.  I have a few ideas, but they
> >     all
> >     need to be more thoroughly thought out and there are some holes and
> >     issues to address.  I viewed this feature as non-essential for an
> >     initial proof of concept, and am glad that we can have design
> >     discussions about it in the open.
> >
> >     So in short, yes, I think the ability to differentiate that certain
> >     rules are required for a module to work and others are optional is
> >     definitely needed.  But I'm not yet set on what the best way to do that
> >     is.  One key goal here is that a developer of a component should be
> >     able
> >     to add policy with fairly minimal knowledge of SELinux.  I'd prefer it
> >     if most of the time they could do the right thing without knowing about
> >     optional, but I'm not yet sure what the best/cleanest way to achieve
> >     that will be.
> >
> >
> > Optional blocks have, in practice, been a huge source of errors I
> > believe.
>  > [snip]
>
> I agree pretty much 100% with everything you've said here about the
> usage and historical limitations of optional.  Thanks for the added
> historical context from before my time.
>

I am not a fan of optionals either. Disabling optionals has been a
source of many bugs in CIL, but it would have been hard to make
translating binary modules to CIL work without them.

> On the topic of packaging, I'll admit that I'm sparse on details without
> an actual implementation at this point, so the packaging aspect of
> Cascade is currently vaporware, but my hope is that an integrated
> packaging and build system framework, inspired by rust's cargo can solve
> a lot of the packaging problems much more cleanly (by inserting optional
> blocks for install order problems during compilation rather than in
> source for example).
>
> I like the suggestion of a question mark operator for optional policy
> quite a bit.  Although I'm really interested in exploring whether it's
> possible to just treat the entirety of it as a policy level dependency
> resolution problem.  Basically annotate with modules a particular module
> depends on vs which are optional - the distinction being that the
> optional marking is done at the module level rather than the
> rule/interface call level.  That might be less heavy-weight and error
> prone to use while still providing the needed flexibility.
>

99% of the time optionals are used as a way of including rules when a
module is present without causing an error when it is not, so this
should provide everything that is needed.

Since you have a lot of freedom, I would recommend a system like that
rather than optionals.

Jim


> > Anyway - forgive me crashing in with all of my opinions. I hope my
> > background on the problems of optionals might at least be helpful.
>
> Opinions are what I'm seeking. :)  And yes, I think all of your thoughts
> here are quite helpful.  I think the attributes concern is a good one
> that we aimed to address, and can continue to refine as needed, and the
> optional thoughts are extremely helpful, since as I mentioned in my
> prior e-mail, the overall support for differentiating which policy is
> required and which is optional is a must-have in my view, but how
> exactly to specify it in a way that is clear is somewhat challenging and
> subjective.  Added info on historical context and use cases is a
> valuable input to that discussion.
>
> -Daniel

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-11-09 18:39 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-04 18:13 [RFC] Cascade: a high level SELinux policy language Daniel Burgener
2021-11-05 19:19 ` James Carter
2021-11-08 20:43   ` Daniel Burgener
     [not found]     ` <CA+EEuAhzFYQhLMXKgAOy_bzhdJV3a0Rqp9YSSot16+e32Vhv6Q@mail.gmail.com>
2021-11-09 18:16       ` Daniel Burgener
2021-11-09 18:39         ` James Carter

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.