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 <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?
> 
> 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;

Reply via email to