On March 25, 2017 at 9:56:03 PM, Gwynne Raskind (gwy...@darkrainfall.org)
wrote:


On Mar 25, 2017, at 19:27, Elijah Johnson via swift-evolution <
swift-evolution@swift.org> wrote:


On March 25, 2017 at 7:15:59 PM, Elijah Johnson (ejrx7...@gmail.com) wrote:




On March 25, 2017 at 10:24:23 AM, Elijah Johnson (ejrx7...@gmail.com) wrote:




On March 23, 2017 at 12:01:48 PM, Joe Groff (jgr...@apple.com) wrote:


On Mar 22, 2017, at 7:25 PM, Elijah Johnson <ejrx7...@gmail.com> wrote:

On March 22, 2017 at 8:41:25 PM, Joe Groff (jgr...@apple.com) wrote:


> On Mar 22, 2017, at 4:07 PM, Elijah Johnson <ejrx7...@gmail.com> wrote:
>
> Hi,
>
> Note that this thread has branched off a bit, so my latest proposal and
the “head” of this thread can be found at
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170320/034189.html

>
>
>
> Can you give an example of this corruption which would be exploitable in
a web server context? An example where, having caught the force-unwrap or
other precondition fatalError, that the web server would face more danger
from continued execution that it would loose by crashing?
>
> The optional has been triggered, the request has been stopped, and
incoming requests are going to a new process, but there are a few threads
open still finishing what they were doing - I’d like to see a good example
of the danger caused by a real “inconsistency”. Lets assume also that all
objects shared between threads are Swift objects and not “UnsafePointers”,
which is a very fair assumtion for a web server. Java even allows native
access and they don’t even crash there.

When considering security threats, we have to take the presence of an
exploit as given until we prove otherwise. A precondition failure indicates
a logic error somewhere in the program, and while safe Swift abstractions
are intended not to lead to memory unsafety in the face of precondition
failures, there's plenty of relatively young, unsafe code below the hood in
the implementations of those abstractions, written by humans who make
mistakes. Whatever lurking security bugs there may be, they're more likely
to be exploitable if you're already in a situation where assumptions have
been violated.

> I’m sorry, but I completely fail to grasp the danger as being > crashing.

Crashing is inconvenient. The user may have to retry their request or
relaunch their app. Security breaches or data corruption are disasters that
can have unbounded impact and cost—you can't undisclose sensitive data.

> I’d be interested to know who these web server developers (ex. Kitura,
Vapor) are targeting without any form of crash handling and if they read
these threads. It really limits the pool of developers more so than on apps
because a single crash on the app ie equivelant to a failed request, not a
crashed web server. I realize you are not competing with Java, but I do not
see yet the compelling reason for no crash handling.
>
> The “actors” with thread pool and proccesses is one idea, but I think
these servers are aiming also for speed and scaleability - don’t know if
they would accept this model. I know that it does get used, and do work for
a company that uses it on their backend (just plain Java, not sep.
processes). Their front-end probably runs like a pre-fork server, but Java
is so stable that there is simply no need for that.

You can use processes for fault isolation today, and that will have some
cost. At Swift's current maturity level, that's really probably the only
responsible isolation strategy. The goal of "actors" would be to get most
of the benefits of processes through language-level isolation without
paying the full cost of processes.

-Joe


I have no personal objection to actors or processes or anything else. I
would just emphasize that the webservers in existence for Swift (and quite
well funded) are right now on a “crash the whole thing” model AFAIK. I
don’t know if they will be able to get by with catching all the
precondition failures in testing - maybe they will - maybe not, but I see
people either wisely turning down Swift for web development or getting
their first crash as a “zero-day” system down event where some guy has to
ssh in and actually start the server back up.

I haven't worked directly with server people that much personally, but on
the opportunities when I have been able to talk to people working in this
space, it sounds like they definitely want something better.

But whatever the fix is, or nothing, they (developers of Perfect, Kitura,
Vapor, etc) will have to like it and implement it. If they’re not
interested, I’m not starting a development company to compete.

I don't see a problem with people developing frameworks to the best of the
platform's ability today and refining their approach as new capabilities
get developed.

And also the development time is so short on my idea that you basically
just have to approve it and the development time for it is hours not months
or years. Just add a fatalError function override and any c developer could
have it done in minutes like this guy
https://github.com/ankurp/unsafe-swift (not
endorsing the post, just showing evidence that setjmp and longjmp work fine
with swift).

setjmp and longjmp do *not* work well with Swift since they need compiler
support to implement their semantics, and since Swift does not provide this
support, setjmp-ing from Swift is undefined behavior. Empirical evidence
that small examples appear to work is not a good way of evaluating UB,
since any changes to Swift or LLVM optimizations may break it. Ease of
implementation is also not a good criterion for designing things.
*Supporting* a trap hook is not easy; it still has serious language
semantics and runtime design issues, and may limit our ability to do
something better.

-Joe


Yeah, I suppose. Sounds like it is still about 2-3 years off.


But…. what happens when a shared or shared sub-process trips? If something
about the process was shared, then it will end up tripping every other
process except some master process which will re-generate them.

Concerning longjmp, it is possible to call from Swift into C, and then from
C into Swift (not in the example, but in general). Therefore, assuming that
the execution state of the C function is still on the stack at the moment
that the exception trips, the jump won’t necessarily involve the Swift
runtime or compiler at all, so far as I can see, aside from leaked memory.
Granted I don’t know that much about the runtime, but an example might be
useful.

The linked example is was done inline, so a bit different than I was
thinking.

BTW, not sure why no one mentioned it, but apparently the whole idea
proposed is already possible without any proposal actually needed. A bit
too complex for me and dangerous looking, but heres a nice post with it
already done.

https://www.cocoawithlove.com/blog/2016/02/02/partial-functions-part-two-catching-precondition-failures.html#setting-up-a-mach-exception-handler


How about going half way on a proposal for a “fatalError” callback, which
would take a “c” function (or be accessible only from c) to prevent
recursion. ie. if the handler was in Swift the callback would then be
liable to induce another fatalError.

The purpose of which would be to log the fatal error string to a file.
int fatalErrorCallback(char* message, char* stacktrace);

Any other usages would be unsupported and something to discuss in the dev
channel (no bearing on the ABI or compiler design, only the reverse). If it
returns “0” then Swift omits its own std output, but in either case it
exits.


One can see easily from the error printout that Swift is running its own
callback, even in Swift:


fatal error: unexpectedly found nil while unwrapping an Optional value

Current stack trace:

0    TestJmp1                           0x0000000104b11410
swift_reportError + 132

1    TestJmp1                           0x0000000104b2e7c0
_swift_stdlib_reportFatalError + 61

2    TestJmp1                           0x000000010489c550 specialized
specialized StaticString.withUTF8Buffer<A> ((UnsafeBufferPointer<UInt8>) ->
A) -> A + 355

3    TestJmp1                           0x0000000104a9e7f0 partial apply
for (_fatalErrorMessage(StaticString, StaticString, StaticString, UInt,
flags : UInt32) -> Never).(closure #2) + 109

4    TestJmp1                           0x000000010489c550 specialized
specialized StaticString.withUTF8Buffer<A> ((UnsafeBufferPointer<UInt8>) ->
A) -> A + 355

5    TestJmp1                           0x0000000104a59170 specialized
_fatalErrorMessage(StaticString, StaticString, StaticString, UInt, flags :
UInt32) -> Never + 96

6    TestJmp1                           0x00000001047f87f0 (closure #1) +
221

7    TestJmp1                           0x00000001047f8a30 @objc (closure
#1) + 9

8    TestJmp1                           0x00000001047f8ae0 runCode + 49

9    TestJmp1                           0x00000001047f8700 main + 87

10   libdyld.dylib                      0x00007fffe1deb254 start + 1

Illegal instruction: 4

If all you can do is log an alternative to what Swift would output anyway,
what's the use case? And certainly permitting more things to happen in that
callback falls under the same caveats as an in-process crash reporter -
compromised context, uncertain data state, very few safe operations.

-- Gwynne Raskind


By “in process crash reporter” are you referring to the link above (
https://www.cocoawithlove.com/blog/2016/02/02/partial-functions-part-two-catching-precondition-failures.html#setting-up-a-mach-exception-handler
)?

The difference between that, and using longjmp (defering the judgment of
what the side effects are to another channel than evolution) would be that
one has specificly caught a "fatalError" and not something else. It
contains the error message and stack trace easily avaiable, and is not
confusable with another "EXE bad instruction”.

As to the supported use case, it would be to write the stack trace to a
file and then exit, or similar operation using isolated C functions. We can
see that the current handler allocates memory and runs instructions on them
in the same thread before it exits. The supported use would be to do the
same, ideally in C which does not compile fatalError instructions (causing
recursion), but uses its own signals to crash.

Not every process wants to pipe its output and error somewhere besides the
console or /dev/null. I’m not aware exactly what currently exists for crash
reporting on Swift, so maybe this is redundant also.

Then, certain developers can discuss the runtime impact of unwiding the
stack via a c longjmp, and weigh its impact in their particular use case,
but not in the forum of swift evolution.

Lets see, in Errors.cpp, you have a function called reportNow (called by
swift_fatalError) with this line:

asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", message);

but it is only for Apple platforms. So you will need a user-defined
callback for linux platforms, in case their linux distro has a system log
they want to write to. Or whatever they want to do with logging.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to