The following patch tightens the pledges for ftp(1).

This provides some additional guarantees, including that ftp(1) cannot
spawn child processes.  This is a significant security win for
sysupgrade(8).

I hope I did not mess up the diff - this is my first time submitting one.

Index: usr.bin/ftp/main.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/main.c,v
retrieving revision 1.131
diff -u -p -u -r1.131 main.c
--- usr.bin/ftp/main.c  11 Feb 2020 18:41:39 -0000      1.131
+++ usr.bin/ftp/main.c  2 May 2020 19:31:40 -0000
@@ -483,27 +483,39 @@ main(volatile int argc, char *argv[])
        (void)signal(SIGWINCH, setttywidth);
 
        if (argc > 0) {
+               int i, needs_exec = 0;
                if (isurl(argv[0])) {
-                       if (pipeout) {
 #ifndef SMALL
-                               if (pledge("stdio rpath dns tty inet proc exec 
fattr",
-                                   NULL) == -1)
-                                       err(1, "pledge");
-#else
-                               if (pledge("stdio rpath dns tty inet fattr",
-                                   NULL) == -1)
-                                       err(1, "pledge");
+                       for (i = 0; i < argc; ++i) {
+                               if (*(argv[i]) == '\0')
+                                       errx(1, "empty URL not allowed");
+                               else if (strncasecmp("http:/", argv[i], 6) &&
+                                   strncasecmp("https:/", argv[i], 7) &&
+                                   strncasecmp("file:", argv[i], 5) &&
+                                   argv[i][strlen(argv[i])] == '/')
+                                       needs_exec = 1;
+                       }
 #endif
+                       if (pipeout) {
+                               if (needs_exec) {
+                                       if (pledge("stdio rpath dns tty inet 
proc exec fattr",
+                                           NULL) == -1)
+                                               err(1, "pledge");
+                               } else {
+                                       if (pledge("stdio rpath dns tty inet 
fattr",
+                                           NULL) == -1)
+                                               err(1, "pledge");
+                               }
                        } else {
-#ifndef SMALL
-                               if (pledge("stdio rpath wpath cpath dns tty 
inet proc exec fattr",
-                                   NULL) == -1)
-                                       err(1, "pledge");
-#else
-                               if (pledge("stdio rpath wpath cpath dns tty 
inet fattr",
-                                   NULL) == -1)
-                                       err(1, "pledge");
-#endif
+                               if (needs_exec) {
+                                       if (pledge("stdio rpath wpath cpath dns 
tty inet proc exec fattr",
+                                           NULL) == -1)
+                                               err(1, "pledge");
+                               } else {
+                                       if (pledge("stdio rpath wpath cpath dns 
tty inet fattr",
+                                           NULL) == -1)
+                                               err(1, "pledge");
+                               }
                        }
 
                        rval = auto_fetch(argc, argv, outfile);

Reply via email to