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