
FreeBSD – a lesson in poor defaults - Basile
https://vez.mrsk.me/freebsd-defaults.txt?hn
======
vacri
Previous discussion:
[https://news.ycombinator.com/item?id=11318508](https://news.ycombinator.com/item?id=11318508)

------
stonogo
This person means well, but suffers from the same myopia a lot of security-
first people do: making these changes to default settings is a huge violation
of expectations, and the changes need to be widely publicized once they are
decided upon. Suddenly dropping support mid-cycle for tons of things will
result in pitchforks and torches from people who, despite the constant
insinuations of this document, do in fact know what they are doing.

This document, in short, makes a great to-do list but completely ignores the
roadbuilding that needs to happen to get people ready and on board.

~~~
byuu
I have to agree.

I'm reminded of OpenBSD's move in 6.0 to enforce W^X on binaries. This breaks
the use of my cooperative threading library: in order to avoid requiring
specific compilers/assemblers (for the portion that's impossible to write in
pure C), I use ~50 bytes of pre-compiled code so that it'll compile anywhere.
To do that, I have to mark the block R|X. But I can't know with 100%
_certainty_ that the codepage doesn't overlap with something that was writable
(since there is no mgetprotect), so I have no choice but to set R|W|X.

So probably what I'll have to end up doing is allocate at least three
codepages at run-time, set to R|W, copy the code there, then set R|X, and take
a performance penalty for needing a pointer to the code block.

What I would like to see FreeBSD do to help with migrating to stronger
security is something like "freebsd-harden" that you run once after a new
installation or version upgrade, and it will walk you through a series of
yes/no prompts, and advise, "if you aren't sure, say no."

~~~
JoshTriplett
(Note: I agree with your main point that changing defaults can cause problems,
and security needs to balance with usability or people won't use it.)

For that 50-byte block of code, on most platforms, you could tell the compiler
or linker to put it in the text section directly along with the rest of the
code, rather than in the data section. A linker script or a section attribute
can do that. Then you can just call it using the appropriate symbol.

I just tested this, with a manually assembled array of bytes, using both of
those methods, and both of them work.

Here's the linker script approach:

    
    
        /tmp$ cat main.c
        unsigned long long add(unsigned long long, unsigned long long);
    
        int main(void)
        {
            return add(23, 45);
        }
        /tmp$ cat add.c
        unsigned char add[] = {
            0x48, 0x89, 0xf8, /* mov %rdi,%rax */
            0x48, 0x01, 0xf0, /* add %rsi,%rax */
            0xc3,             /* retq */
        };
        /tmp$ cat demo.ld
        SECTIONS {
            .text : {
                main.o(.text);
                add.o(.data);
            }
        }
        /tmp$ gcc -c main.c -o main.o
        /tmp$ gcc -c add.c -o add.o
        /tmp$ gcc demo.ld -o demo
        /tmp$ ./demo ; echo $?
        68
    

While this won't work on every possible platform, in practice it'll work for
almost any platform you might care about.

~~~
byuu
Wow, that's very neat! Thank you! Does Clang support this as well?

It looks like I don't need the main.o(.text) line either, which is good
because that would be a large burden on users of the library.

Also, just noting for others, I had to use .text : { libco.o(.rdata); } since
my char array was const.

~~~
JoshTriplett
> Wow, that's very neat! Thank you!

Glad I could help. Thank _you_ for building awesome software.

> Does Clang support this as well?

Clang supports __attribute__((section)).

For linker script support, it'd depend on what linker you use. GNU ld and gold
have complete support for linker scripts. LLVM's lld has some support for
linker scripts, plenty enough to do things like this, though it may lack some
features that GNU ld and gold support.

> It looks like I don't need the main.o(.text) line either, which is good
> because that would be a large burden on users of the library.

When I attempted to link without that, the linker complained that it couldn't
find main. Interesting that it worked for you without that. You can also use
wildcards to match all object files, if that helps, and then use "ld -T
thescript.ld *.o" to link.

> Also, just noting for others, I had to use .text : { libco.o(.rdata); }
> since my char array was const.

Sadly, read-only sections vary a bit more; some compilers use .rdata, some use
.rodata.

You could use __attribute__((section)) to explicitly put the array in a
specific section, then name that section in the linker script; that avoids the
warning and any platform-specific inconsistency.

~~~
byuu
> When I attempted to link without that, the linker complained that it
> couldn't find main. Interesting that it worked for you without that.

My guess would be because I also had main.o on the command line? It looks like
yours didn't have that.

> LLVM's lld has some support for linker scripts, plenty enough to do things
> like this

Hmmm, well just throwing out alternative ideas ... I could try something like
this:

    
    
        __attribute__((aligned(4096)))
        static const unsigned char co_swap_function[4096] = { ... };
        VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges);
        //or
        mprotect((void*)base, size, PROT_READ | PROT_EXEC);
    

The theory being that the const will put it into either .rdata or .rodata
(since nobody can decide on one or the other it seems); and then by forcing
the alignment to a page boundary and also filling a page boundary, we make
sure the VirtualProtect or mprotect call won't affect anything other than our
co_swap function. But even if it does, it'll most likely be more read-only
data, and it's not the end of the world if that gets marked executable.

The downside is of course that the page size isn't really known at compile-
time. On ?nix, it's a run-time call to sysconf(_SC_PAGESIZE); but on Windows
I'm not sure how to get that value. However, I'm pretty sure it's going to be
4K on any x86/amd64 systems.

So, these seem to be all of our possible options:

1\. we use inline assembly; and now you require a specific assembler (MSVC and
GCC inline ASM syntax are totally different) or additional tools like
nasm/yasm. I really don't understand why at least three people have favored
this solution now; but since they haven't elaborated any reasons, I'll just
have to politely agree to disagree here :/

2\. we use __attribute__((section)), and get unsuppressible warning messages,
and the command also won't work with MSVC.

3\. we use __attribute__((section)) with our own name, and use a linker script
to suppress the warning message, losing compatibility with MSVC.

4\. we use __attribute__((aligned(4096))), risk the page size being wrong, and
the attribute won't work with MSVC.

5\. we use #include <stdalign.h> [when _MSC_VER isn't defined] +
alignas(4096), risk the page size being wrong, and require C11 instead of C89
to compile. [_Alignas probably isn't going to be in MSVC due to their hatred
of C99 and above.]

For the latter two, we can have #ifndef/#define LIBCO_PAGE_SIZE 4096, for
convenient command-line overrides.

Probably the most pragmatic route will be to support multiple options and let
the user override if one of them doesn't work out on their platform for some
reason.

EDIT: here we go:

    
    
        SYSTEM_INFO si;
        GetSystemInfo(&si);
        int page_size = si.dwPageSize;
    

Then for good measure, we throw in:

    
    
        assert(LIBCO_PAGE_SIZE == si.dwPageSize);  //or for ?nix, == sysconf(_SC_PAGESIZE)

~~~
JoshTriplett
MSVC also has mechanisms to manipulate where data ends up in the final binary;
you'd just need to use those mechanisms on Windows.

But yes, approach 5 seems the most portable.

------
sverige
It sounds like he needs an OS built on "default deny" principles. The best one
for that is OpenBSD, and he recommends porting over three or four packages
from OpenBSD. Really, he'd be happier running that, I think. I know I was when
I first started exploring the BSDs. I tried FreeBSD, PC-BSD, and DragonflyBSD
before settling on OpenBSD.

Default deny makes the most sense if you are interested in security. Sure, it
can be a PITA to set up .conf files at first and get the packages you need,
but once past the learning curve, it's the simplest thing to maintain.

FreeBSD reminds me a lot of various flavors of Linux I've tried in the
(distant) past. All kinds of stuff running by default, old packages for
compatibility, etc.

Security may not be important for many people till it's too late, but it's one
of those things that pays dividends in what _doesn 't_ happen. Hard to sell if
you've never been pwned.

~~~
micro_softy
You never tried NetBSD?

If you are suggesting NetBSD has more things enabled by default than OpenBSD I
would bet that is incorrect. I have tried a lot of different projects and
NetBSD is the best I have seen for not enabling anything. It forces you to
figure things out.

Whenever I read OpenBSD mailing lists or blogs, they often seem more
aggressive in trying to make their users adhere to the default system
provided. That's fine, but NetBSD generally does not do this. Users are not
assumed to be idiots and are not discouraged from experimentation.

The BSD projects share more similarities than differences. None of them
require anyone to use the entire base system or the defaults. Users can
compile their own kernels, write their own configs e.g., based on examples
provided, and cherry pick utilities.[1] In my opinion this is made just a tad
easier than with Linux.

1\. But if you do this with OpenBSD and advertise it, I think you may draw
some criticism. Frankensystem, etc. They are not encouraging experimentation,
they are encouraging conformity.

------
tachion
A lot of these points have been addressed in one way or another - 11.0-RELEASE
has a new installer dialog[0] with multiple hardening options available. These
are OFF by default in 11.0-RELEASE due to POLA principle, but they are to be
enabled to ON by default in future releases (hopefully in 11.1).

[0]
[https://secure.freshbsd.org/commit/freebsd/r302897](https://secure.freshbsd.org/commit/freebsd/r302897)

------
fowl2
So, uh, why doesn't he just use OpenBSD? They take security seriously. (not
being snarky, really!)

~~~
jlgaddis
I'm pretty sure he does. I think he's an OpenBSD developer.

~~~
gonzo
TJ isn't a dev, but he's a fan of OpenBSD.

------
loeg
Minor nit: HPN has been dropped from openssh since this was written.

~~~
unethical_ban
Why would high performance networking be dropped from the default? I learned
of its existence a few weeks ago and was wondering when it would make it in.

~~~
loeg
No one was available to benchmark HPN vs no-HPN to illustrate it still made a
difference.

------
cpach
Dupe:
[https://hn.algolia.com/?query=FreeBSD:%20a%20lesson%20in%20p...](https://hn.algolia.com/?query=FreeBSD:%20a%20lesson%20in%20poor%20defaults&sort=byDate&dateRange=all&type=story&storyText=false&prefix&page=0)

------
X86BSD
Not to mention he doesn't understand what flipping these defaults actually
will do.

They sound great but without understanding exactly what happens when some of
these switches are flipped you're going to wind up breaking other things
because you simply do not have the knowledge to understand these features in
depth.

His heart may be in the right place but he needs more experience and wisdom on
how things work on a more fundamental level.

------
karma_vaccum123
My least favorite FreeBSD default: permissions for CD/DVD burning.

I get the high-minded position FreeBSD takes here, but it is also a total PITA
and it seems pretty clear that if you are putting a CD/DVD in a host's tray,
you have console access.

~~~
byuu
Yeah, it's pretty nuts having to study the output of camcontrol and /dev,
creating a devfs ruleset, adding that to /etc/rc.conf, adding your CD drive
into /etc/fstab, and then tweaking a sysctl, just to burn a CD.

I am hard-pressed to think of the security risks involved in a user being able
to burn a CD. Short of some kind of highly-confidential server with no
internet access, where you'd probably want the whole machine inside a locked
cage anyway.

~~~
toast0
There's a cd in the tray, but we don't know who put it there. Maybe if you're
logged in on a specific terminal?

I could contrive some scenarios where it would be undesirable though: Maybe if
there's a rewritable (or not finalized write once) disc also in the system for
something important? Let's say, a diskless system without pxe support, so it
boots from a cd drive, but doesn't mount it. An unauthorized user with access
to the burner could disrupt the next boot.

