From nobody Fri Apr 1 22:51:51 2022 X-Original-To: freebsd-hackers@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id D4B1E1A5227B for ; Fri, 1 Apr 2022 22:51:54 +0000 (UTC) (envelope-from sigsys@gmail.com) Received: from mail-qv1-xf34.google.com (mail-qv1-xf34.google.com [IPv6:2607:f8b0:4864:20::f34]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "smtp.gmail.com", Issuer "GTS CA 1D4" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4KVb5Q074Rz4hgh for ; Fri, 1 Apr 2022 22:51:54 +0000 (UTC) (envelope-from sigsys@gmail.com) Received: by mail-qv1-xf34.google.com with SMTP id b17so3112850qvf.12 for ; Fri, 01 Apr 2022 15:51:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:date:mime-version:user-agent:content-language:to :references:from:subject:in-reply-to:content-transfer-encoding; bh=nzRagAcsO0CP9g+9D8KePydI8IZxPlpSM7iBH9r3VBQ=; b=QRBYj3WcFaj0imX7l8x5TuXQqSB1NFR/crNNH0vINAIhFuPtnO9nnvYbdqJ049NTdD gsQD73s6JpzFy4+cI/KjE/xfm/h1EVTsMBU4k8WuW2AM23V2T4+Rz9b7AKBnK5P55JYx GpWv/TMgEoJN6m4uPUGyqKx20mOQAmLb3us4P7CyIzhdWdwVXSVqy77L767lqBM006XY 2eZ4LlFdwrFHiHF1yfRR6i7mhDKU+oy+RcmfwqWV6eDKSO4oBRHHKrWqJcRElIh0Bw2S OuEIB9IF08KZwl61E+1YSIEUgIddYe3ymkWBti8R8ilxTWyOGFXM2ne+YsmxiczdfYGl RObA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent :content-language:to:references:from:subject:in-reply-to :content-transfer-encoding; bh=nzRagAcsO0CP9g+9D8KePydI8IZxPlpSM7iBH9r3VBQ=; b=BtFhJmxIlwLmts242mMYNf9ikyvytPR315Y7x78h0WesdKhJgzUvDhNdEXpnGtFBXU h0Qa5z5xcIUIaFOhw6EV+Itk1bDg1abwrqGiktrB/y1OUub3maimJaq5MElw7kloV+k4 kOgmMbBZVM6wgxngSLOXc6iUF69L6EVPh6AthlyOyw3bk2i77fG4QhI31b/meIYc/o73 Okc3tAFb6hjSqkgsmIeuIov4GNMGHCa5W2ogjGwF8P4UAjJaOwD1oD33NUDo8XqQCEQ6 MvIGAYK8TY4Gxhqmjy5dXOGvOUfNpUho7jG5gA0SIlK6Ztxj6hReWrdczBKpAgfBOIlZ ka1A== X-Gm-Message-State: AOAM530bI61xK4tMnxgX/liza86KH5OzGA6mooTA5IsSKKOAziGhl8fg YvLRhK659LO4aB4BzQ2sU2KN9TYURpg= X-Google-Smtp-Source: ABdhPJyxR6fYyq1ztsgGpdMHo0eqXW/yHjsRDs6OhAI9Pb9XPlALVl+rTLjgNkRuxRvdOmH5xy8HWA== X-Received: by 2002:a05:6214:d42:b0:441:831b:fa1b with SMTP id 2-20020a0562140d4200b00441831bfa1bmr34068529qvr.130.1648853513048; Fri, 01 Apr 2022 15:51:53 -0700 (PDT) Received: from [10.0.0.2] ([162.156.254.107]) by smtp.gmail.com with ESMTPSA id h14-20020a05622a170e00b002e1a65754d8sm2749330qtk.91.2022.04.01.15.51.52 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 01 Apr 2022 15:51:52 -0700 (PDT) Message-ID: <84f115a9-62e9-669c-24c3-caa9d7cbecb7@gmail.com> Date: Fri, 1 Apr 2022 18:51:51 -0400 List-Id: Technical discussions relating to FreeBSD List-Archive: https://lists.freebsd.org/archives/freebsd-hackers List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-freebsd-hackers@freebsd.org MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:91.0) Gecko/20100101 Thunderbird/91.7.0 Content-Language: en-US To: freebsd-hackers@freebsd.org References: <25b5c60f-b9cc-78af-86d7-1cc714232364@gmail.com> <01320c49-fa7e-99d2-5840-3c61bb8c0d57@FreeBSD.org> <2d103b77-84d4-fbd7-d957-21b9aa4d5d79@gmail.com> <16ab7cdb-32b4-5ffe-f6a8-a657383b3078@FreeBSD.org> <202204011037.231AbmQ7002360@critter.freebsd.dk> From: Mathieu Subject: Re: curtain: WIP sandboxing mechanism with pledge()/unveil() support In-Reply-To: <202204011037.231AbmQ7002360@critter.freebsd.dk> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 4KVb5Q074Rz4hgh X-Spamd-Bar: --- Authentication-Results: mx1.freebsd.org; dkim=pass header.d=gmail.com header.s=20210112 header.b=QRBYj3Wc; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (mx1.freebsd.org: domain of sigsys@gmail.com designates 2607:f8b0:4864:20::f34 as permitted sender) smtp.mailfrom=sigsys@gmail.com X-Spamd-Result: default: False [-4.00 / 15.00]; RCVD_VIA_SMTP_AUTH(0.00)[]; R_SPF_ALLOW(-0.20)[+ip6:2607:f8b0:4000::/36:c]; FREEMAIL_FROM(0.00)[gmail.com]; TO_DN_NONE(0.00)[]; RCVD_COUNT_THREE(0.00)[3]; DKIM_TRACE(0.00)[gmail.com:+]; DMARC_POLICY_ALLOW(-0.50)[gmail.com,none]; NEURAL_HAM_SHORT(-1.00)[-1.000]; FROM_EQ_ENVFROM(0.00)[]; MIME_TRACE(0.00)[0:+]; FREEMAIL_ENVFROM(0.00)[gmail.com]; ASN(0.00)[asn:15169, ipnet:2607:f8b0::/32, country:US]; MID_RHS_MATCH_FROM(0.00)[]; DWL_DNSWL_NONE(0.00)[gmail.com:dkim]; ARC_NA(0.00)[]; NEURAL_HAM_MEDIUM(-1.00)[-1.000]; R_DKIM_ALLOW(-0.20)[gmail.com:s=20210112]; FROM_HAS_DN(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; MIME_GOOD(-0.10)[text/plain]; PREVIOUSLY_DELIVERED(0.00)[freebsd-hackers@freebsd.org]; RCPT_COUNT_ONE(0.00)[1]; RCVD_IN_DNSWL_NONE(0.00)[2607:f8b0:4864:20::f34:from]; MLMMJ_DEST(0.00)[freebsd-hackers]; RCVD_TLS_ALL(0.00)[] X-ThisMailContainsUnwantedMimeParts: N On 4/1/22 06:37, Poul-Henning Kamp wrote: > -------- > David Chisnall writes: > >>> pledge()/unveil() are usually used for fairly well-disciplined >>> applications that either don't run other programs or run very specific >>> programs that are also well-disciplined and don't expect too much >>> (unless you just drop the pledges on execve()). >> The execve hole is the reason that I have little interest in pledge as >> an enforcement mechanism. > That (and the name) is why I have never seen it as an enforcement mechanism, but only as a special case of asserts: > > "I pledge that I'm not going to ... (until I tell you otherwise), fail me if I do". > > It is not obvious to me what role the "curtain" proposal is intended to play, > or what role the originator of that proposal think pledge()/unveil() has ? Not sure how I would define what pledge()/unveil() are on OpenBSD.  I think that they don't like the words "containers" or "sandboxes" for some reason (those are poorly defined terms anyway).  I have more often seen it described as an "exploit-mitigation" mechanism.  I believe that reducing the kernel attack surface was a big priority for them (while it's more of a secondary goal for me).  But as far as I can tell, the enforcement is solid.  How much of a "sandbox" it really is depends on the pledge promises and unveils that you use.  The "execve hole" is just there if you ask for it. And it's a bit difficult to explain how curtain/pledge are different as mechanisms without enumerating all of the details that are different.  But they added up enough that I thought it was better to give it a different name and a different API rather than trying to mold pledge() into something it wasn't designed to be.  And with a separate API I didn't have to worry about breaking pledge()/unveil() compatibility all the time. The main problems I had with pledge()/unveil() for my goals were: 1) pledge() is capable of sandboxing unsuspecting programs but only to some extent.  There are a lot of little details that will make many programs fail.  With curtain(1) you can get much more of a real UNIX-like environment while (hopefully!) remaining isolated.  And what really helped with that was that on FreeBSD, kernel access checks were already modularized.  So it's much easier to expose more kernel functionality while maintaining isolation. 2) pledge() is nestable, but unveil() is not.  Once you "commit" your unveils, you can't ever use unveil() again (nor can any of the programs you execute).  And unveil is essential for sandboxing.  That's a problem if you, say, run a whole shell session sandboxed, and then try to sandbox something within it (or run something that tries to self-sandbox itself automatically). Or say if you wanted to sandbox firefox as a whole on top of firefox using pledge()/unveil() internally (to get proper isolation in-between its own processes as well).  All of this works with my curtain module. 3) I wanted restrictions to be more configurable in userland (partly to help with testing applications).  I didn't want to have to modify the kernel every time I wanted to add permissions for a certain sysctl, ioctl, privilege, socket option, etc.  That's the main reason I used a completely different API.  Also, on OpenBSD, the paths allowed by certain promises (e.g. "/dev/stdout" for "stdio", "/etc/resolv.conf" for "dns", etc) are hardcoded in the kernel and the semantics are different than from user unveils.  I moved this to the userland too and there's a unified method to unveil paths (which also helps fixing problem 2). 4) unveil() doesn't reveal the directory "skeleton" above the paths that you unveil (you generally get ENOENT trying to stat() or list parent directories).  This makes a lot of programs unhappy (especially GUI ones).  With curtain(1) by default you get a filtered view of the FS instead (but the unveil(3) compatibility still behaves like on OpenBSD). To run unsuspecting programs, you'd use the curtain(1) utility.  And there's a configuration system to manage permissions.  This does not use pledge() at all anywhere, it uses a new curtain(3) API (and the underlying curtainctl(2) syscall). I think the nearest analogy to curtain(1) is "firejail" on Linux, not pledge(). > What is the level of ambition and the use-cases here ? > To easily run EVERYTHING sandboxed.  Realistically it won't be able to.  But it's the goal.  If a program doesn't work, then why not?  It should. For desktop apps, the main problems are programs that ignore $TMPDIR, dbus/dconf and untrusted X11 problems.  And many KDE apps that need their own separate XDG directories to work for now. But browsers work, audio players work, gimp works, qbittorrent works, libreoffice works if you give it access to /tmp. Sandboxing whole shell sessions work.  You can build/run untrusted programs and confine the whole thing to the current directory (but you need to be very careful with the way you run git in it for example).  These aren't things that you do with pledge(), but it's what curtain(1) was designed to do and it tries to make it convenient. There are other use cases, like something I'd call "last-ditch" sandboxing for server programs that need to run as root (say to authenticate users and switch credentials).  It's possible to run samba for example with read-only access to the needed system files, read-write access to its own state/logs directories and restrict its access to specific data directories you want to share.  I believe that this can maintain system integrity if samba is compromised.  This becomes a bit like "traditional MAC" with the integrity labels, but it can be setup on an application-by-application basis rather than the whole system.  It might not be worth it if the most important thing on the server to begin with are those data directories, but at the very least it could make forensics easier if there's a breach.  There are examples of this in the sample config file.