On Mon, Oct 03, 2022 at 06:43:26PM -0600, Theo de Raadt wrote:
> David Gwynne <da...@gwynne.id.au> 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?

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:23:17 -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
@@ -93,6 +93,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 +148,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:23:18 -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;

Reply via email to