On Tue, Oct 04, 2022 at 09:43:40AM +0000, Klemens Nanni wrote:
> On Tue, Oct 04, 2022 at 09:24:04AM +0000, Klemens Nanni wrote:
> > On Mon, Oct 03, 2022 at 06:43:26PM -0600, Theo de Raadt wrote:
> > > David Gwynne <[email protected]> wrote:
> > >
> > > > On Sun, Oct 02, 2022 at 06:32:04PM +0000, Klemens Nanni wrote:
> > > > > diskless(8) just needs tftpd(8) to deliver files, none of the possibly
> > > > > untrusted clients are supposed to ever write anything.
> > > > >
> > > > > Either way, even when run without -c, a single file writable by _tftpd
> > > > > might be enough for a malicious client to fill up the server's disk.
> > > > >
> > > > > A proper read-only mode ("stdio rpath dns inet") seems much safer.
> > > >
> > > > agreed. i'm ok with this diff, but it's worth asking if we can make the
> > > > default read-only and ask people to opt in for write (and create) before
> > > > this specific diff goes in. ie, read-only be default, '-w' to enable
> > > > write mode, '-c' to enable write+create?
> > >
> > > we were read-only believers a long time ago, and it seems the world has
> > > caught up to our way of thinking so yes maybe it is time to make it an
> > > option you must specify.
> >
> > I like the idea, then -c should logically imply -w.
> >
> > Feedback? OK?
>
> Now with the important manual bits explaining the new defaul.t
ok by me.
>
> Index: tftpd.8
> ===================================================================
> RCS file: /cvs/src/usr.sbin/tftpd/tftpd.8,v
> retrieving revision 1.8
> diff -u -p -r1.8 tftpd.8
> --- tftpd.8 4 Mar 2019 01:06:03 -0000 1.8
> +++ tftpd.8 4 Oct 2022 09:42:16 -0000
> @@ -37,7 +37,7 @@
> .Nd Trivial File Transfer Protocol daemon
> .Sh SYNOPSIS
> .Nm tftpd
> -.Op Fl 46cdiv
> +.Op Fl 46cdivw
> .Op Fl l Ar address
> .Op Fl p Ar port
> .Op Fl r Ar socket
> @@ -53,11 +53,13 @@ does not require an account or password
> Due to the lack of authentication information,
> .Nm
> will allow only publicly readable files to be accessed.
> +By default files may only be read, unless the
> +.Fl w
> +option is specified.
> Files may be written only if they already exist and are publicly writable,
> unless the
> .Fl c
> -flag is specified
> -.Pq see below .
> +flag is specified.
> Note that this extends the concept of
> .Dq public
> to include
> @@ -93,6 +95,9 @@ Allow new files to be created;
> otherwise uploaded files must already exist.
> Files are created with default permissions
> allowing anyone to read or write to them.
> +.Pp
> +This option implies
> +.Fl w .
> .It Fl d
> Do not daemonize.
> If this option is specified,
> @@ -145,6 +150,8 @@ to
> on startup;
> the remote host is not expected to pass the directory
> as part of the file name to transfer.
> +.It Fl w
> +Allow files to be written to.
> .El
> .Sh SEE ALSO
> .Xr tftp 1 ,
> Index: tftpd.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/tftpd/tftpd.c,v
> retrieving revision 1.48
> diff -u -p -r1.48 tftpd.c
> --- tftpd.c 4 Oct 2022 07:05:28 -0000 1.48
> +++ tftpd.c 4 Oct 2022 09:42:26 -0000
> @@ -283,12 +283,13 @@ __dead void
> usage(void)
> {
> extern char *__progname;
> - fprintf(stderr, "usage: %s [-46cdiv] [-l address] [-p port] [-r socket]"
> + fprintf(stderr, "usage: %s [-46cdivw] [-l address] [-p port] [-r
> socket]"
> " directory\n", __progname);
> exit(1);
> }
>
> int cancreate = 0;
> +int canwrite = 0;
> int verbose = 0;
> int debug = 0;
> int iflag = 0;
> @@ -309,7 +310,7 @@ main(int argc, char *argv[])
> int family = AF_UNSPEC;
> int devnull = -1;
>
> - while ((c = getopt(argc, argv, "46cdil:p:r:v")) != -1) {
> + while ((c = getopt(argc, argv, "46cdil:p:r:vw")) != -1) {
> switch (c) {
> case '4':
> family = AF_INET;
> @@ -318,7 +319,7 @@ main(int argc, char *argv[])
> family = AF_INET6;
> break;
> case 'c':
> - cancreate = 1;
> + canwrite = cancreate = 1;
> break;
> case 'd':
> verbose = debug = 1;
> @@ -342,6 +343,9 @@ main(int argc, char *argv[])
> case 'v':
> verbose = 1;
> break;
> + case 'w':
> + canwrite = 1;
> + break;
> default:
> usage();
> /* NOTREACHED */
> @@ -394,9 +398,12 @@ main(int argc, char *argv[])
> if (cancreate) {
> if (pledge("stdio rpath wpath cpath fattr dns inet", NULL) ==
> -1)
> lerr(1, "pledge");
> - } else {
> + } else if (canwrite) {
> if (pledge("stdio rpath wpath fattr dns inet", NULL) == -1)
> lerr(1, "pledge");
> + } else {
> + if (pledge("stdio rpath dns inet", NULL) == -1)
> + lerr(1, "pledge");
> }
>
> event_init();
> @@ -969,6 +976,9 @@ validate_access(struct tftp_client *clie
> int fd, wmode;
> const char *errstr, *filename;
> char rewritten[PATH_MAX];
> +
> + if (!canwrite && mode != RRQ)
> + return (EACCESS);
>
> if (strcmp(requested, SEEDPATH) == 0) {
> char *buf;