From: Seth Forshee <seth.forshee@canonical.com>
To: Stephen Smalley <sds@tycho.nsa.gov>
Cc: Serge Hallyn <serge.hallyn@canonical.com>,
selinux@tycho.nsa.gov, linux-kernel@vger.kernel.org,
Andy Lutomirski <luto@amacapital.net>,
linux-security-module@vger.kernel.org,
Alexander Viro <viro@zeniv.linux.org.uk>,
James Morris <james.l.morris@oracle.com>,
linux-fsdevel@vger.kernel.org,
Casey Schaufler <casey@schaufler-ca.com>
Subject: Re: [PATCH 6/7] selinux: Ignore security labels on user namespace mounts
Date: Fri, 24 Jul 2015 10:11:37 -0500 [thread overview]
Message-ID: <20150724151137.GA82891@ubuntu-hedt> (raw)
In-Reply-To: <20150723162331.GB25235@ubuntu-hedt>
On Thu, Jul 23, 2015 at 11:23:31AM -0500, Seth Forshee wrote:
> On Thu, Jul 23, 2015 at 11:36:03AM -0400, Stephen Smalley wrote:
> > On 07/23/2015 10:39 AM, Seth Forshee wrote:
> > > On Thu, Jul 23, 2015 at 09:57:20AM -0400, Stephen Smalley wrote:
> > >> On 07/22/2015 04:40 PM, Stephen Smalley wrote:
> > >>> On 07/22/2015 04:25 PM, Stephen Smalley wrote:
> > >>>> On 07/22/2015 12:14 PM, Seth Forshee wrote:
> > >>>>> On Wed, Jul 22, 2015 at 12:02:13PM -0400, Stephen Smalley wrote:
> > >>>>>> On 07/16/2015 09:23 AM, Stephen Smalley wrote:
> > >>>>>>> On 07/15/2015 03:46 PM, Seth Forshee wrote:
> > >>>>>>>> Unprivileged users should not be able to supply security labels
> > >>>>>>>> in filesystems, nor should they be able to supply security
> > >>>>>>>> contexts in unprivileged mounts. For any mount where s_user_ns is
> > >>>>>>>> not init_user_ns, force the use of SECURITY_FS_USE_NONE behavior
> > >>>>>>>> and return EPERM if any contexts are supplied in the mount
> > >>>>>>>> options.
> > >>>>>>>>
> > >>>>>>>> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
> > >>>>>>>
> > >>>>>>> I think this is obsoleted by the subsequent discussion, but just for the
> > >>>>>>> record: this patch would cause the files in the userns mount to be left
> > >>>>>>> with the "unlabeled" label, and therefore under typical policies,
> > >>>>>>> completely inaccessible to any process in a confined domain.
> > >>>>>>
> > >>>>>> The right way to handle this for SELinux would be to automatically use
> > >>>>>> mountpoint labeling (SECURITY_FS_USE_MNTPOINT, normally set by
> > >>>>>> specifying a context= mount option), with the sbsec->mntpoint_sid set
> > >>>>>> from some related object (e.g. the block device file context, as in your
> > >>>>>> patches for Smack). That will cause SELinux to use that value instead
> > >>>>>> of any xattr value from the filesystem and will cause attempts by
> > >>>>>> userspace to set the security.selinux xattr to fail on that filesystem.
> > >>>>>> That is how SELinux normally deals with untrusted filesystems, except
> > >>>>>> that it is normally specified as a mount option by a trusted mounting
> > >>>>>> process, whereas in your case you need to automatically set it.
> > >>>>>
> > >>>>> Excellent, thank you for the advice. I'll start on this when I've
> > >>>>> finished with Smack.
> > >>>>
> > >>>> Not tested, but something like this should work. Note that it should
> > >>>> come after the call to security_fs_use() so we know whether SELinux
> > >>>> would even try to use xattrs supplied by the filesystem in the first place.
> > >>>>
> > >>>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > >>>> index 564079c..84da3a2 100644
> > >>>> --- a/security/selinux/hooks.c
> > >>>> +++ b/security/selinux/hooks.c
> > >>>> @@ -745,6 +745,30 @@ static int selinux_set_mnt_opts(struct super_block *sb,
> > >>>> goto out;
> > >>>> }
> > >>>> }
> > >>>> +
> > >>>> + /*
> > >>>> + * If this is a user namespace mount, no contexts are allowed
> > >>>> + * on the command line and security labels must be ignored.
> > >>>> + */
> > >>>> + if (sb->s_user_ns != &init_user_ns) {
> > >>>> + if (context_sid || fscontext_sid || rootcontext_sid ||
> > >>>> + defcontext_sid) {
> > >>>> + rc = -EACCES;
> > >>>> + goto out;
> > >>>> + }
> > >>>> + if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
> > >>>> + struct block_device *bdev = sb->s_bdev;
> > >>>> + sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
> > >>>> + if (bdev) {
> > >>>> + struct inode_security_struct *isec =
> > >>>> bdev->bd_inode;
> > >>>
> > >>> That should be bdev->bd_inode->i_security.
> > >>
> > >> Sorry, this won't work. bd_inode is not the inode of the block device
> > >> file that was passed to mount, and it isn't labeled in any way. It will
> > >> just be unlabeled.
> > >>
> > >> So I guess the only real option here as a fallback is
> > >> sbsec->mntpoint_sid = current_sid(). Which isn't great either, as the
> > >> only case where we currently assign task labels to files is for their
> > >> /proc/pid inodes, and no current policy will therefore allow create
> > >> permission to such files.
> > >
> > > Darn, you're right, that isn't the inode we want. There really doesn't
> > > seem to be any way to get back to the one we want from the LSM, short of
> > > adding a new hook.
> >
> > Maybe list_first_entry(&sb->s_bdev->bd_inodes, struct inode, i_devices)?
> > Feels like a layering violation though...
>
> Yeah, and even though that probably works out to be the inode we want in
> most cases I don't think we can be absolutely certain that it is. Maybe
> there's some way we could walk the list and be sure we've found the
> right inode, but I'm not seeing it.
I guess we could do something like this (note that most of the changes
here are just to give a version of blkdev_get_by_path which takes a
struct path * so that the filename lookup doesn't have to be done
twice). Basically add a new hook that informs the security module of the
inode for the backing device file passed to mount and call that from
mount_bdev. The security module could grab a reference to the inode and
stash it away.
Something else to note is that, as I have it here, the hook would end up
getting called for every mount of a given block device, not just the
first. So it's possible the security module could see the hook called a
second time with a different inode that has a different label. The hook
could be changed to return int if you wanted to have the opportunity to
reject such mounts.
Seth
---
diff --git a/fs/block_dev.c b/fs/block_dev.c
index f8ce371c437c..dc2173e24e30 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1372,14 +1372,39 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
}
EXPORT_SYMBOL(blkdev_get);
+static struct block_device *__lookup_bdev(struct path *path);
+
+struct block_device * __blkdev_get_by_path(struct path *path, fmode_t mode,
+ void *holder)
+{
+ struct block_device *bdev;
+ int err;
+
+ bdev = __lookup_bdev(path);
+ if (IS_ERR(bdev))
+ return bdev;
+
+ err = blkdev_get(bdev, mode, holder);
+ if (err)
+ return ERR_PTR(err);
+
+ if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) {
+ blkdev_put(bdev, mode);
+ return ERR_PTR(-EACCES);
+ }
+
+ return bdev;
+}
+EXPORT_SYMBOL(__blkdev_get_by_path);
+
/**
* blkdev_get_by_path - open a block device by name
- * @path: path to the block device to open
+ * @pathname: path to the block device to open
* @mode: FMODE_* mask
* @holder: exclusive holder identifier
*
- * Open the blockdevice described by the device file at @path. @mode
- * and @holder are identical to blkdev_get().
+ * Open the blockdevice described by the device file at @pathname.
+ * @mode and @holder are identical to blkdev_get().
*
* On success, the returned block_device has reference count of one.
*
@@ -1389,25 +1414,22 @@ EXPORT_SYMBOL(blkdev_get);
* RETURNS:
* Pointer to block_device on success, ERR_PTR(-errno) on failure.
*/
-struct block_device *blkdev_get_by_path(const char *path, fmode_t mode,
+struct block_device *blkdev_get_by_path(const char *pathname, fmode_t mode,
void *holder)
{
struct block_device *bdev;
- int err;
-
- bdev = lookup_bdev(path);
- if (IS_ERR(bdev))
- return bdev;
+ struct path path;
+ int error;
- err = blkdev_get(bdev, mode, holder);
- if (err)
- return ERR_PTR(err);
+ if (!pathname || !*pathname)
+ return ERR_PTR(-EINVAL);
- if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) {
- blkdev_put(bdev, mode);
- return ERR_PTR(-EACCES);
- }
+ error = kern_path(pathname, LOOKUP_FOLLOW, &path);
+ if (error)
+ return ERR_PTR(error);
+ bdev = __blkdev_get_by_path(&path, mode, holder);
+ path_put(&path);
return bdev;
}
EXPORT_SYMBOL(blkdev_get_by_path);
@@ -1702,6 +1724,30 @@ int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
EXPORT_SYMBOL(ioctl_by_bdev);
+static struct block_device *__lookup_bdev(struct path *path)
+{
+ struct block_device *bdev;
+ struct inode *inode;
+ int error;
+
+ inode = d_backing_inode(path->dentry);
+ error = -ENOTBLK;
+ if (!S_ISBLK(inode->i_mode))
+ goto fail;
+ error = -EACCES;
+ if (!may_open_dev(path))
+ goto fail;
+ error = -ENOMEM;
+ bdev = bd_acquire(inode);
+ if (!bdev)
+ goto fail;
+out:
+ return bdev;
+fail:
+ bdev = ERR_PTR(error);
+ goto out;
+}
+
/**
* lookup_bdev - lookup a struct block_device by name
* @pathname: special file representing the block device
@@ -1713,7 +1759,6 @@ EXPORT_SYMBOL(ioctl_by_bdev);
struct block_device *lookup_bdev(const char *pathname)
{
struct block_device *bdev;
- struct inode *inode;
struct path path;
int error;
@@ -1724,23 +1769,9 @@ struct block_device *lookup_bdev(const char *pathname)
if (error)
return ERR_PTR(error);
- inode = d_backing_inode(path.dentry);
- error = -ENOTBLK;
- if (!S_ISBLK(inode->i_mode))
- goto fail;
- error = -EACCES;
- if (!may_open_dev(&path))
- goto fail;
- error = -ENOMEM;
- bdev = bd_acquire(inode);
- if (!bdev)
- goto fail;
-out:
+ bdev = __lookup_bdev(&path);
path_put(&path);
return bdev;
-fail:
- bdev = ERR_PTR(error);
- goto out;
}
EXPORT_SYMBOL(lookup_bdev);
diff --git a/fs/super.c b/fs/super.c
index 008f938e3ec0..558f7845a171 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -34,6 +34,7 @@
#include <linux/fsnotify.h>
#include <linux/lockdep.h>
#include <linux/user_namespace.h>
+#include <linux/namei.h>
#include "internal.h"
@@ -980,15 +981,26 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
{
struct block_device *bdev;
struct super_block *s;
+ struct path path;
+ struct inode *inode;
fmode_t mode = FMODE_READ | FMODE_EXCL;
int error = 0;
if (!(flags & MS_RDONLY))
mode |= FMODE_WRITE;
- bdev = blkdev_get_by_path(dev_name, mode, fs_type);
- if (IS_ERR(bdev))
- return ERR_CAST(bdev);
+ if (!dev_name || !*dev_name)
+ return ERR_PTR(-EINVAL);
+
+ error = kern_path(dev_name, LOOKUP_FOLLOW, &path);
+ if (error)
+ return ERR_PTR(error);
+
+ bdev = __blkdev_get_by_path(&path, mode, fs_type);
+ if (IS_ERR(bdev)) {
+ error = PTR_ERR(bdev);
+ goto error;
+ }
/*
* once the super is inserted into the list by sget, s_umount
@@ -1040,6 +1052,10 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
bdev->bd_super = s;
}
+ inode = d_backing_inode(path.dentry);
+ security_sb_backing_dev(s, inode);
+ path_put(&path);
+
return dget(s->s_root);
error_s:
@@ -1047,6 +1063,7 @@ error_s:
error_bdev:
blkdev_put(bdev, mode);
error:
+ path_put(&path);
return ERR_PTR(error);
}
EXPORT_SYMBOL(mount_bdev);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4597420ab933..3748945bf0d5 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2315,6 +2315,8 @@ extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long);
extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long);
extern int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder);
+extern struct block_device *__blkdev_get_by_path(struct path *path, fmode_t mode,
+ void *holder);
extern struct block_device *blkdev_get_by_path(const char *path, fmode_t mode,
void *holder);
extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode,
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 9429f054c323..52ce1a094e04 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1351,6 +1351,7 @@ union security_list_options {
int (*sb_clone_mnt_opts)(const struct super_block *oldsb,
struct super_block *newsb);
int (*sb_parse_opts_str)(char *options, struct security_mnt_opts *opts);
+ void (*sb_backing_dev)(struct super_block *sb, struct inode *inode);
int (*dentry_init_security)(struct dentry *dentry, int mode,
struct qstr *name, void **ctx,
u32 *ctxlen);
@@ -1648,6 +1649,7 @@ struct security_hook_heads {
struct list_head sb_set_mnt_opts;
struct list_head sb_clone_mnt_opts;
struct list_head sb_parse_opts_str;
+ struct list_head sb_backing_dev;
struct list_head dentry_init_security;
#ifdef CONFIG_SECURITY_PATH
struct list_head path_unlink;
diff --git a/include/linux/security.h b/include/linux/security.h
index 79d85ddf8093..7a4d8382af20 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -231,6 +231,7 @@ int security_sb_set_mnt_opts(struct super_block *sb,
int security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb);
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
+void security_sb_backing_dev(struct super_block *sb, struct inode *inode);
int security_dentry_init_security(struct dentry *dentry, int mode,
struct qstr *name, void **ctx,
u32 *ctxlen);
@@ -562,6 +563,10 @@ static inline int security_sb_parse_opts_str(char *options, struct security_mnt_
return 0;
}
+static inline void security_sb_backing_dev(struct super_block *sb,
+ struct inode *inode)
+{ }
+
static inline int security_inode_alloc(struct inode *inode)
{
return 0;
diff --git a/security/security.c b/security/security.c
index 062f3c997fdc..f6f89e0f06d8 100644
--- a/security/security.c
+++ b/security/security.c
@@ -347,6 +347,11 @@ int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
}
EXPORT_SYMBOL(security_sb_parse_opts_str);
+void security_sb_backing_dev(struct super_block *sb, struct inode *inode)
+{
+ call_void_hook(sb_backing_dev, sb, inode);
+}
+
int security_inode_alloc(struct inode *inode)
{
inode->i_security = NULL;
@@ -1595,6 +1600,8 @@ struct security_hook_heads security_hook_heads = {
LIST_HEAD_INIT(security_hook_heads.sb_clone_mnt_opts),
.sb_parse_opts_str =
LIST_HEAD_INIT(security_hook_heads.sb_parse_opts_str),
+ .sb_backing_dev =
+ LIST_HEAD_INIT(security_hook_heads.sb_backing_dev),
.dentry_init_security =
LIST_HEAD_INIT(security_hook_heads.dentry_init_security),
#ifdef CONFIG_SECURITY_PATH
next prev parent reply other threads:[~2015-07-24 15:11 UTC|newest]
Thread overview: 106+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-07-15 19:46 [PATCH 0/7] Initial support for user namespace owned mounts Seth Forshee
2015-07-15 19:46 ` [PATCH 1/7] fs: Add user namesapace member to struct super_block Seth Forshee
2015-07-16 2:47 ` Eric W. Biederman
2015-08-05 21:03 ` Seth Forshee
2015-08-05 21:19 ` Eric W. Biederman
2015-08-06 14:20 ` Seth Forshee
2015-08-06 14:51 ` Stephen Smalley
2015-08-06 15:44 ` Seth Forshee
2015-08-06 16:11 ` Stephen Smalley
2015-08-07 14:16 ` Seth Forshee
2015-08-07 14:32 ` Seth Forshee
2015-08-07 18:35 ` Casey Schaufler
2015-08-07 18:57 ` Seth Forshee
2015-07-15 19:46 ` [PATCH 2/7] userns: Simpilify MNT_NODEV handling Seth Forshee
2015-07-15 19:46 ` [PATCH 3/7] fs: Ignore file caps in mounts from other user namespaces Seth Forshee
2015-07-15 21:48 ` Serge E. Hallyn
2015-07-15 21:50 ` Andy Lutomirski
2015-07-15 22:35 ` Eric W. Biederman
2015-07-16 1:14 ` Seth Forshee
2015-07-16 1:23 ` Andy Lutomirski
2015-07-16 13:06 ` Seth Forshee
2015-07-16 1:19 ` Andy Lutomirski
2015-07-16 4:23 ` Eric W. Biederman
2015-07-16 4:49 ` Andy Lutomirski
2015-07-16 5:04 ` Eric W. Biederman
2015-07-16 5:15 ` Andy Lutomirski
2015-07-16 5:44 ` Eric W. Biederman
2015-07-16 13:13 ` Seth Forshee
2015-07-17 0:43 ` Eric W. Biederman
2015-07-29 16:04 ` Serge E. Hallyn
2015-07-29 16:18 ` Serge E. Hallyn
2015-07-15 19:46 ` [PATCH 4/7] fs: Treat foreign mounts as nosuid Seth Forshee
2015-07-17 6:46 ` Nikolay Borisov
2015-07-15 19:46 ` [PATCH 5/7] security: Restrict security attribute updates for userns mounts Seth Forshee
2015-07-15 19:46 ` [PATCH 6/7] selinux: Ignore security labels on user namespace mounts Seth Forshee
2015-07-16 13:23 ` Stephen Smalley
2015-07-22 16:02 ` Stephen Smalley
2015-07-22 16:14 ` Seth Forshee
2015-07-22 20:25 ` Stephen Smalley
2015-07-22 20:40 ` Stephen Smalley
2015-07-23 13:57 ` Stephen Smalley
2015-07-23 14:39 ` Seth Forshee
2015-07-23 15:36 ` Stephen Smalley
2015-07-23 16:23 ` Seth Forshee
2015-07-24 15:11 ` Seth Forshee [this message]
2015-07-30 15:57 ` Stephen Smalley
2015-07-30 16:24 ` Seth Forshee
2015-07-15 19:46 ` [PATCH 7/7] smack: Don't use security labels for " Seth Forshee
2015-07-15 20:43 ` Casey Schaufler
2015-07-15 20:36 ` [PATCH 0/7] Initial support for user namespace owned mounts Casey Schaufler
2015-07-15 21:06 ` Eric W. Biederman
2015-07-15 21:48 ` Seth Forshee
2015-07-15 22:28 ` Eric W. Biederman
2015-07-16 1:05 ` Andy Lutomirski
2015-07-16 2:20 ` Eric W. Biederman
2015-07-16 13:12 ` Stephen Smalley
2015-07-15 23:04 ` Casey Schaufler
2015-07-15 22:39 ` Casey Schaufler
2015-07-16 1:08 ` Andy Lutomirski
2015-07-16 2:54 ` Casey Schaufler
2015-07-16 4:47 ` Eric W. Biederman
2015-07-17 0:09 ` Dave Chinner
2015-07-17 0:42 ` Eric W. Biederman
2015-07-17 2:47 ` Dave Chinner
2015-07-21 17:37 ` J. Bruce Fields
2015-07-22 7:56 ` Dave Chinner
2015-07-22 14:09 ` J. Bruce Fields
2015-07-22 16:52 ` Austin S Hemmelgarn
2015-07-22 17:41 ` J. Bruce Fields
2015-07-23 1:51 ` Dave Chinner
2015-07-23 13:19 ` J. Bruce Fields
2015-07-23 23:48 ` Dave Chinner
2015-07-18 0:07 ` Serge E. Hallyn
2015-07-20 17:54 ` Colin Walters
2015-07-16 11:16 ` Lukasz Pawelczyk
2015-07-17 0:10 ` Eric W. Biederman
2015-07-17 10:13 ` Lukasz Pawelczyk
2015-07-16 3:15 ` Eric W. Biederman
2015-07-16 13:59 ` Seth Forshee
2015-07-16 15:09 ` Casey Schaufler
2015-07-16 18:57 ` Seth Forshee
2015-07-16 21:42 ` Casey Schaufler
2015-07-16 22:27 ` Andy Lutomirski
2015-07-16 23:08 ` Casey Schaufler
2015-07-16 23:29 ` Andy Lutomirski
2015-07-17 0:45 ` Casey Schaufler
2015-07-17 0:59 ` Andy Lutomirski
2015-07-17 14:28 ` Serge E. Hallyn
2015-07-17 14:56 ` Seth Forshee
2015-07-21 20:35 ` Seth Forshee
2015-07-22 1:52 ` Casey Schaufler
2015-07-22 15:56 ` Seth Forshee
2015-07-22 18:10 ` Casey Schaufler
2015-07-22 19:32 ` Seth Forshee
2015-07-23 0:05 ` Casey Schaufler
2015-07-23 0:15 ` Eric W. Biederman
2015-07-23 5:15 ` Seth Forshee
2015-07-23 21:48 ` Casey Schaufler
2015-07-28 20:40 ` Seth Forshee
2015-07-30 16:18 ` Casey Schaufler
2015-07-30 17:05 ` Eric W. Biederman
2015-07-30 17:25 ` Seth Forshee
2015-07-30 17:33 ` Eric W. Biederman
2015-07-17 13:21 ` Seth Forshee
2015-07-17 17:14 ` Casey Schaufler
2015-07-16 15:59 ` Seth Forshee
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20150724151137.GA82891@ubuntu-hedt \
--to=seth.forshee@canonical.com \
--cc=casey@schaufler-ca.com \
--cc=james.l.morris@oracle.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=luto@amacapital.net \
--cc=sds@tycho.nsa.gov \
--cc=selinux@tycho.nsa.gov \
--cc=serge.hallyn@canonical.com \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).