[Service] Provide access control of file system 19/247019/14
authorYoungsoo Choi <kenshin.choi@samsung.com>
Fri, 6 Nov 2020 04:53:58 +0000 (20:53 -0800)
committerYoungsoo Choi <kenshin.choi@samsung.com>
Wed, 18 Nov 2020 06:33:16 +0000 (22:33 -0800)
This considers as below to provide access control of file system:

- Prevent direct access to oiginal fs module from service app
- Override |require] not to load modules from invalid path

Together with:
https://review.tizen.org/gerrit/247016/

Change-Id: I13fd7298810fc46cc2a0eb987bc6a475be366788
Signed-off-by: Youngsoo Choi <kenshin.choi@samsung.com>
wrt_app/service/device_api_router.ts

index a7e356348dfb8d4602d1f6320a90c04c42ba3179..e129a358c74530e775cd806d48787e407c0fed44 100644 (file)
@@ -1,4 +1,5 @@
 import { wrt } from '../browser/wrt';
+const Module = require('module');
 
 export class DeviceAPIRouter {
   currentApplication: any;
@@ -16,6 +17,8 @@ export class DeviceAPIRouter {
   packageId: string;
   callerAppId: string;
   permissions: string[];
+  sharedPaths: string[];
+  validPaths: string[];
 
   constructor(id: string, isGlobal: boolean) {
     this.id = id;
@@ -24,8 +27,31 @@ export class DeviceAPIRouter {
     this.callerAppId = ids[1] ?? '';
     this.packageId = this.serviceId.split('.')[0];
     this.permissions = [];
+    this.sharedPaths = [
+      '/opt/usr/apps/shared/res/',
+      '/opt/usr/globalapps/shared/res/'
+    ];
+    this.validPaths = [
+      '/bin/emps/empPepperPlugins/',
+      `/home/owner/apps_rw/${this.packageId}/`,
+      '/home/owner/content/',
+      '/home/owner/share/',
+      '/media/',
+      '/opt/media/',
+      '/opt/share/',
+      `/opt/usr/apps/${this.packageId}/`,
+      '/opt/usr/apps/pepper/',
+      `/opt/usr/globalapps/${this.packageId}/`,
+      `/opt/usr/home/owner/apps_rw/${this.packageId}/`,
+      '/opt/usr/home/owner/content/',
+      '/opt/usr/home/owner/share/',
+      '/tmp/',
+      '/usr/bin/emps/empPepperPlugins/',
+      '/usr/share/wrt/'
+    ];
 
     this.initWebapis();
+    this.refineResolveFilename();
     if (isGlobal) {
       this.permissions = wrt.getPrivileges(this.id);
       this.refineApplicationApis();
@@ -37,25 +63,62 @@ export class DeviceAPIRouter {
   }
 
   initWebapis() {
+    let app_info = global.tizen.application.getAppInfo(this.serviceId);
+    if (app_info) {
+      this.packageId = app_info.packageId;
+    }
     global.webapis = global.webapis ?? {};
-
     global.webapis.getCallerAppId = () => {
       return this.callerAppId;
     }
+    global.webapis.getPackageId = () => {
+      return this.packageId;
+    }
+    global.webapis.getPermissions = () => {
+      return this.permissions;
+    }
     global.webapis.getServiceId = () => {
       return this.serviceId;
     }
-    let app_info = global.tizen.application.getAppInfo(this.serviceId);
-    if (app_info) {
-      this.packageId = app_info.packageId;
-    }
-    global.webapis.getPackageId = () => {
-      return this.packageId;
+    global.webapis.isValidPath = (path: string) => {
+      let ret = false;
+      for (const validPath of this.validPaths) {
+        if (path.startsWith(validPath))
+          return true;
+      }
+      for (const sharedPath of this.sharedPaths) {
+        if (path.replace(`${path.split('/')[4]}/`, '').includes(sharedPath))
+          return true;
+      }
+      return false;
     }
+    Object.defineProperties(global.webapis, {
+      getCallerAppId: { writable: false, enumerable: true },
+      getPackageId: { writable: false, enumerable: true },
+      getPermissions: { writable: false, enumerable: true },
+      getServiceId: { writable: false, enumerable: true },
+      isValidPath: { writable: false, enumerable: true },
+    });
     this.initEdgeWebapis();
     this.initProductWebapis();
   }
 
+  refineResolveFilename() {
+    const originalResolveFilename = Module._resolveFilename;
+    Module._resolveFilename = function(...args: any[]) {
+      let path = '';
+      if (args[0] === 'fs') {
+        path = originalResolveFilename('fs_tizen', args[1], args[2]);
+      } else {
+        path = originalResolveFilename(...args);
+      }
+      if (path.startsWith('/') && !global.webapis.isValidPath(path))
+        throw new Error(`Invalid access to ${path}`);
+      return path;
+    }
+    Object.defineProperty(Module, '_resolveFilename', { writable: false });
+  }
+
   initEdgeWebapis() {
     if (wrt['edge'] && !global.webapis.edge) {
       let edge = wrt.edge as NativeWRTjs.EdgeExtension;