Преглед на файлове

Kernel: Add unveil('b')

This is a new "browse" permission that lets you open (and subsequently list
contents of) directories underneath the path, but not regular files or any other
types of files.
Sergey Bugaev преди 4 години
родител
ревизия
098070b767
променени са 5 файла, в които са добавени 30 реда и са изтрити 6 реда
  1. 4 0
      Base/usr/share/man/man2/unveil.md
  2. 2 0
      Kernel/FileSystem/ProcFS.cpp
  3. 19 5
      Kernel/FileSystem/VirtualFileSystem.cpp
  4. 1 0
      Kernel/Process.h
  5. 4 1
      Kernel/Syscalls/unveil.cpp

+ 4 - 0
Base/usr/share/man/man2/unveil.md

@@ -28,6 +28,7 @@ include the following characters:
 * `w`: May write to a file at this path
 * `x`: May execute a program image at this path
 * `c`: May create or remove a file at this path
+* `b`: May browse directories at this path
 
 A single `unveil()` call may specify multiple permission characters at once.
 Subsequent `unveil()` calls may take away permissions from the ones allowed
@@ -78,6 +79,9 @@ unveil("/etc/WindowServer/WindowServer.ini", "rwc");
 // Allow the process to execute Calendar:
 unveil("/bin/Calendar", "x");
 
+// Allow the process to browse files from /usr/share:
+unveil("/usr/share", "b");
+
 // Disallow any further veil manipulation:
 unveil(nullptr, nullptr);
 ```

+ 2 - 0
Kernel/FileSystem/ProcFS.cpp

@@ -644,6 +644,8 @@ static Optional<KBuffer> procfs$pid_unveil(InodeIdentifier identifier)
             permissions_builder.append('x');
         if (unveiled_path.permissions & UnveiledPath::Access::CreateOrRemove)
             permissions_builder.append('c');
+        if (unveiled_path.permissions & UnveiledPath::Access::Browse)
+            permissions_builder.append('b');
         obj.add("permissions", permissions_builder.to_string());
     }
     array.finish();

+ 19 - 5
Kernel/FileSystem/VirtualFileSystem.cpp

@@ -825,7 +825,13 @@ const UnveiledPath* VFS::find_matching_unveiled_path(StringView path)
     for (auto& unveiled_path : Process::current()->unveiled_paths()) {
         if (path == unveiled_path.path)
             return &unveiled_path;
-        if (path.starts_with(unveiled_path.path) && path.length() > unveiled_path.path.length() && path[unveiled_path.path.length()] == '/')
+        if (!path.starts_with(unveiled_path.path))
+            continue;
+        // /foo/ and /foo/bar
+        if (unveiled_path.path.ends_with('/'))
+            return &unveiled_path;
+        // /foo and /foo/bar
+        if (path.length() > unveiled_path.path.length() && path[unveiled_path.path.length()] == '/')
             return &unveiled_path;
     }
     return nullptr;
@@ -863,10 +869,18 @@ KResult VFS::validate_path_against_process_veil(StringView path, int options)
         return KSuccess;
     }
     if (options & O_RDONLY) {
-        if (!(unveiled_path->permissions & UnveiledPath::Access::Read)) {
-            dbg() << "Rejecting path '" << path << "' since it hasn't been unveiled with 'r' permission.";
-            dump_backtrace();
-            return KResult(-EACCES);
+        if (options & O_DIRECTORY) {
+            if (!(unveiled_path->permissions & (UnveiledPath::Access::Read | UnveiledPath::Access::Browse))) {
+                dbg() << "Rejecting path '" << path << "' since it hasn't been unveiled with 'r' or 'b' permissions.";
+                dump_backtrace();
+                return KResult(-EACCES);
+            }
+        } else {
+            if (!(unveiled_path->permissions & UnveiledPath::Access::Read)) {
+                dbg() << "Rejecting path '" << path << "' since it hasn't been unveiled with 'r' permission.";
+                dump_backtrace();
+                return KResult(-EACCES);
+            }
         }
     }
     if (options & O_WRONLY) {

+ 1 - 0
Kernel/Process.h

@@ -101,6 +101,7 @@ struct UnveiledPath {
         Write = 2,
         Execute = 4,
         CreateOrRemove = 8,
+        Browse = 16,
     };
 
     String path;

+ 4 - 1
Kernel/Syscalls/unveil.cpp

@@ -49,7 +49,7 @@ int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
     if (!params.path.characters || !params.permissions.characters)
         return -EINVAL;
 
-    if (params.permissions.length > 4)
+    if (params.permissions.length > 5)
         return -EINVAL;
 
     auto path = get_syscall_path_argument(params.path);
@@ -79,6 +79,9 @@ int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
         case 'c':
             new_permissions |= UnveiledPath::Access::CreateOrRemove;
             break;
+        case 'b':
+            new_permissions |= UnveiledPath::Access::Browse;
+            break;
         default:
             return -EINVAL;
         }