Перейти к содержимому

Kimapr

Пользователи
  • Публикации

    24
  • Зарегистрирован

  • Посещение

  • Победитель дней

    4

Сообщения, опубликованные пользователем Kimapr


  1. 2 минуты назад, Totoro сказал:

     

    Будет, будет. ) Главное не переставать шуметь.

    А ты уже потестил новую версию (номер версии я не менял)? Мне интересно твоё мнение о том, как хорошо (/плохо/ужасно/идеально и т.д) всё реализовано.


  2. 2 минуты назад, Totoro сказал:

    Я тебе доступ выдал на проект - чтобы не заморачиваться с пулл-реквестами.

    Реквест смерджил, вечером домой приду, потестирую детальнее.

    А вообще - здорово. )

    Спасибо :)  Скоро я еще мультиплеер сделаю.


  3. 19 минут назад, Totoro сказал:

     

    Мы по такой же схеме игру делали.

    Уже перестали что ли? Жаль, думал будет что-то годное... ☹️

     

    P.s. [offtopic] Может мне тоже туда что-нибудь запилить? Врагов, например [/offtopic]


  4. 45 минут назад, astral17 сказал:

    ммм, у нас походу немного разное понятие boot было, я подумал, что кинуть файл в /boot/*.lua , но вижу был не прав.

    Нет, я действительно говорил про /boot/, но сам я сделал через /lib/core/boot.lua.

    Цитата

    При изменении /lib/core/boot.lua всё нормально запустилось.

    Помоему если уж ты и ставишь свой скрипт в /boot/, ты должен назвать его так, чтобы он выполнялся последним, т.е. ПОСЛЕ других бутскриптов. Например, название

    "zz_tprotect_init.lua" прекрасно подойдет, т.к. z - последняя (или одна из таковых) буква английского алфавита.

    Цитата

    Однако основная мысль прошлого сообщения была в добавке возможности защиты частичной таблиц, т.е. чтобы только некоторые поля были readonly , что позволило бы юзеру с гораздо меньшими усилиями защититься от всего перечисленного выше. Однако хозяин - барин, автор библиотеки не я, поэтому и не я выбираю, что в ней будет, а только предлагаю.

    В своей библиотеке я нарочно допустил брешь, так что если в метатаблице защищаемой таблицы (не зеркальной!) объявлена функция __newindex, то вместо ошибки будет выполнена она. Учитывая это, в __newindex можно реализовать защиту некоторых полей тем, что если их ключ совпадает с поданным в функцию ключём, то ничего не делать, или кинуть эррор.


  5. А можно скриншот ошибки? Я патчил OpenOS 1.7.3, изменив /lib/core/boot.lua:

    ...
    
    local package = dofile("/lib/package.lua")
    local tprotect = dofile("/lib/tprotect.lua")
    do
      -- Unclutter global namespace now that we have the package module and a filesystem
      _G.component = nil
      _G.computer = nil
      _G.process = nil
      _G.unicode = nil
      -- Inject the package modules into the global namespace, as in Lua.
      _G.package = package
    
      -- Initialize the package module with some of our own APIs.
      package.loaded.tprotect = tprotect
      package.loaded.component = component
      package.loaded.computer = computer
      package.loaded.unicode = unicode
      package.loaded.buffer = dofile("/lib/buffer.lua")
      package.loaded.filesystem = dofile("/lib/filesystem.lua")
      package.loaded.color = dofile("/lib/color.lua")
    
      -- Inject the io modules
      _G.io = dofile("/lib/io.lua")
    end
    
    ...
    
    status("Initializing system...")
    
    package.loaded.component = tprotect.protect(component)
    package.loaded.computer = tprotect.protect(computer)
    package.loaded.unicode = tprotect.protect(unicode)
    do
      local loaded=package.loaded
      local unloadable={component=true,computer=true,unicode=true,tprotect=true,filesystem=true}
      local raw_type=type
      function package.unload(name)
        assert(raw_type(name)=="string","bad argument #1 to package.unload (string expected, got "..raw_type(name)..")")
        if not unloadable[name] then
          package.loaded[name]=nil
        end
      end
    end
    package.loaded=tprotect.protect(package.loaded)
    _G.package=tprotect.protect(package)
    
    computer.pushSignal("init") -- so libs know components are initialized.
    require("event").pull(1, "init") -- Allow init processing.
    _G.runlevel = 1
    if gpu and screen then
      gpu.setResolution(gpu.maxResolution())
    end

    Здесь после всех бутскриптов запускается процесс защиты дефолтных либ OpenComputers, а также package. Сам tprotect уже себя защитил.


  6. И вообще, какого чёрта мы опустились до старта системы? Я вообще просто библиотечку для защиты таблиц сделал, а как её использовать - не моё дело (если я не являюсь пользователем, при разработке Kion - я являюсь им)


  7. 1 час назад, astral17 сказал:

    Если сделать package.loaded readonly то вся система сломается к чертям, т.к. не сможет загружать новые библиотеки и т.д. и т.п., ещё проблемка в том, что нужно в таком случае защищать и _G ведь кто мешает подменить package на другую таблицу?, затем кто мешает подменить функцию require ?, заменить require на костыль, который вместо tprotect вернёт заражённую копию?, так что тут как вариант добавить readonly поля по выбору, затем функция не возвращает метатаблицу зеркала, а возвращает метатаблицу оригинала. Когда говорил, что иногда хотелось бы видеть метатаблицы, я имел ввиду через getmetatable . Ну а вообще, для другой системы может и будет внутренняя защита от таких вещей, но это нужно смотреть на то, какая структура будет.

    Я такое в Kion в init поставил и все работает нормально. У библы package есть свой оригинал package.loaded, и он хранится в локальной переменной. Посмотри на код из /lib/package.lua:

    local loaded = {
      ["_G"] = _G,
      ["bit32"] = bit32,
      ["coroutine"] = coroutine,
      ["math"] = math,
      ["os"] = os,
      ["package"] = package,
      ["string"] = string,
      ["table"] = table
    }
    package.loaded = loaded

    А защита _G сломает некоторые программы к чертям. В _G нельзя будет писать, но это ещё не всё! Просто переопределив _G

    _G=tprotect.protect(_G)

    Ничего не получится. Защищена будет только сама переменная, но не таблица глобального окружения. Её нужно будет менять для каждой прожки. В таком случае лучше каждой программе сделать свое глобальное окружение. Это будет легче. А там пусть какую-угодно фигню творят, лишь бы out of memory не было (при должной защите, это единственный краш, который программа сможет нанести системе).


  8. 3 часа назад, astral17 сказал:

    Ну, из уязвимостей вроде бы и всё, конечно же проблема до сих пор возникает "как получить эту библиотеку, если зловред уже работает", т.е. он может спокойно подменить require , package и т.д. , т.е. даже если библиотека загружена, ты не можешь удостовериться в том, что это правда она, однако то, что сама таблица защищена уже гарантирует, что те, кто получил её не обнаружат сюрприз. Как фиксить такое фз, и это уже просто чисто для размышлений (но было бы неплохо, если можно было подтвердить).

    Было бы неплохо, если сам код был под спойлером в теге "код".

    Как знаешь, в таблицах, которые хочешь защитить могут находиться также и другие таблицы. Иногда хочется защитить и их (но не всегда), поэтому хотелось бы видеть функцию, которая будет рекурсивно защищать все таблицы от изменений, которые есть в защищаемой таблице. (не забудь про возможность зацикливания, например в защищаемой таблице может вдруг оказаться ссылка на её саму).

    Ну и на последок, то, что в getmetatable от зеркала возвращается строка защитная, не очень хорошо, иногда хотелось бы видеть метатаблицу, оригинальной (конечно же readonly), тут тогда возникает вопрос, до какой глубины идти?, ответ: до тех пор, пока есть метатаблица у метатаблицы и она ещё не защищена (в кратце расширение к рекурсивной защите). В принципе это будет создавать дополнительные нагрузки на память, поэтому можно поставить флажок, нужно ли так делать.

    Вроде бы большего ожидать от этой библиотеки смысла скорее всего нету (до тех пор, пока она касается только защиты таблиц). А за старания респект.

    UPD:
    короче, нужен багфикс сего чуда

     

      Показать содержимое

    pLReZSn.png

     

    Если вкратце, то при обращении к метаметодам зеркала получается, что оно берёт сырые значения из метатаблицы (вот как раз таки причина, почему у меня не удалась та атака с __add , ну да ладно, она хотя бы показала, что в теории любая глобальная переменная может быть злом), а это может оказаться довольно довольно важной вещью таблицы (т.е. нужно сделать будет редирект всех метаметодов, либо изменить структуру работы).

    Функция protect вместе с зеркалом таблицы возвращает метатаблицу зеркала (на самом деле нет, но она косвенно влияет на настоящую метатаблицу зеркала). Библиотеку нужно подгружать в начале работы системы! Можно вот такой код поместить в /boot/:

    require"tprotect"
    package.loaded.component = tprotect.protect(component)
    package.loaded.computer = tprotect.protect(computer)
    package.loaded.unicode = tprotect.protect(unicode)
    do
      local loaded=package.loaded
      local unloadable={component=true,computer=true,unicode=true,tprotect=true,filesystem=true}
      local raw_type=type
      function package.unload(name)
        assert(raw_type(name)=="string","bad argument #1 to package.unload (string expected, got "..raw_type(name)..")")
        if not unloadable[name] then
          package.loaded[name]=nil
        end
      end
    end
    package.loaded=tprotect.protect(package.loaded)
    _G.package=tprotect.protect(package)

    И постараться чтобы этот бутскрипт выполнился последним (предпологается, что другие бутскрипты хорошие и не вредные!). Еще можно реализовать права на файлы, как в *nix, но для этого я и пишу Kion (это ОСь такая). Чудо щас исправлю


  9. Добрый день(/вечер/ночь/утро), форумчане! Сегодня я начинаю разработку новой ОСи, основанной на OpenOS 1.7.2. Её фичами будут:

    • Защита от изменений таблиц с библиотеками (tprotect рулит!)
    • Распределение прав у программ. Нормальная система пользователей (как в *nix'ах)
    • Графическая оболочка
    • Вытесняющая многозадачность

    Пока что готов только tprotect и заставка.

      Репозиторий


  10. Проблематичненько! Я даже не заметил, что можно их переопределить, как это сделал я. Шас исправим-с.

    Вот патч:

    local getmetatable=getmetatable -- 
    local setmetatable=setmetatable --
    local type=type                 -- Дополнительная зашыта
    local error=error               --
    local assert=assert             --

    Библиотека все еще уязвима к подмене этих функций до её загрузки. Так что её нужно загружать до загрузки чего-либо ещё опасного


  11. 24.01.2019 в 18:22, Kimapr сказал:

    Бывали ли у вас когда-нибудь такие ситуации, когда необходимо защитить какую-либо таблицу от записи? Например, вы пишите операционную систему в OpenComputers,

    и хотите хоть какую-то защиту от вирусов. Бедные таблицы всегда в очень большой опасности. Как овечки. tprotect - это пастух, который защитит ваши таблицы от записи, а когда вы захотите снова в нее что-то записать, вы сможете это сделать (если не потеряете ключ). Вообщем вот ее код (он небольшой):

      Показать содержимое

    local tprotect={}

    local raw_rawset=rawset -- Обязательно! Без этой строки вся библиотека безполезна!
    local protectid=tostring(math.random(10000,99999))
    local nonpi={
      tostring(math.random(10000,99999)),
      tostring(math.random(10000,99999)),
      tostring(math.random(10000,99999)),
      tostring(math.random(10000,99999))
    }
    local function newKey()
      return {math.random(10000,99999)}
    end
    function _G.rawset(t,k,v) -- Ну и без этой функции тоже
      local cantrawset=getmetatable(t)[protectid.."cantrawset"] or t[protectid.."cantrawset"]
      local cantset=getmetatable(t)[protectid.."cantset"] or t[protectid.."cantset"]
      if getmetatable(t).isOpened(protectid) or ((not tprotect.isProtected(t)) and not cantrawset) then
        raw_rawset(t,k,v)
      elseif not cantset then
        t[k]=v
      end
    end
    function tprotect.protect(t) -- Защитить таблицу от записи и вернуть ключ разблокировки
      assert(type(t)=="table","bad argument #1 to protect (table expected, got "..type(t)..")")
      local key=newKey()
      local opened=false
      local mto=getmetatable(t)
      local mt
      local mt2=setmetatable(
        {
          [protectid]=true,
          ___open=function(k)
            if k==key then
              opened=true
              return true
            end
            return false
          end,
          ___close=function(k)
            if k==key then
              opened=false
              return true
            end
          end,
          ___isOpened=function(pi)
            if pi==protectid then
              return opened
            else
              return nil
            end
          end,
          [nonpi[1]]=true,
          [nonpi[2]]=true,
          [nonpi[3]]=true,
          [nonpi[4]]=true,
          ___unprotect=function(k)
            if k==key then
              return mt
            else
              return false
            end
          end
        },
      {__pairs=function(self)return function()end,self,nil end,
       __ipairs=function(self)return function()end,self,0 end,
       __newindex=function(self,k,v)end,
       [protectid.."cantrawset"]=true,
       [nonpi[1].."cantrawset"]=true,
       [nonpi[2].."cantrawset"]=true,
       [nonpi[3].."cantrawset"]=true,
       [nonpi[4].."cantrawset"]=true,
       [protectid.."cantset"]=true,
       [nonpi[1].."cantset"]=true,
       [nonpi[2].."cantset"]=true,
       [nonpi[3].."cantset"]=true,
       [nonpi[4].."cantset"]=true,})
      mt=setmetatable({
        __newindex=function(self,k,v)
          if not opened then
            error("table \""..tostring(self).."\" is protected, you can't write to it!")
          end
          if mto.__newindex then
            return mto.__newindex(self,k,v)
          end
          return raw_rawset(self,k,v)
        end,
        __metatable=mt2
      },{__index=mto,__newindex=function(self,k,v)
          if not opened then
            error("table \""..tostring.."\" is protected, you can't write to it!")
          end
          return raw_rawset(self,k,v)
        end})
      setmetatable(t,mt)
      return key
    end
    function tprotect.open(t,k) -- "Открыть" таблицу: в неё можно будет писать. Для этого нужен ключ разблокировки, который вернул tprotect.protect
      return getmetatable(t).___open(k)
    end
    function tprotect.close(t,k) -- "Закрыть" таблицу: она снова будет защищена от записи. Опять же, нужен ключ.
      return getmetatable(t).___close(k)
    end
    function tprotect.unprotect(t,k) -- Разблокировка таблицы, отмена tprotect.protect. Нужен ключ, а то библиотека безполезна
      local mt,mto=getmetatable(t).___unprotect(k)
      if mt then
        mt.__metatable=nil
        setmetatable(t,mto)
        return true
      else
        return false
      end
    end
    function tprotect.isProtected(t) -- Защищена ли таблица?
      return getmetatable(t)[protectid]
    end
    return tprotect

    А теперь документация, а то я пишу код непонятно:

    
    function tprotect.protect(table:t):table -- Установить защиту на таблицу. После этого в нее нельзя будет записывать, не имея ключ, который эта функция и возвращает. Если у таблицы t была метатаблица, то она останется и будет работать дальше, но сменить её будет нельзя до вызова tprotect.unprotect
    
    function tprotect.open(table:t,table:key):boolean -- "Открыть" таблицу ключем. Если таблица key - это тот самый ключ, который вернула tprotect.protect, то вернёт возможность записи в таблицу.
    
    function tprotect.close(table:t,table:key):boolean -- "Закрыть" таблицу тем же ключем. Обязательно вызывайте эту функцию, после того, как закончите запись или ваша таблица будет снова в опасности.
    
    function tprotect.unprotect(table:t,table:key):boolean -- Отменяет все, что наделала функция tprotect.protect. Вызывайте её, когда вам надоест защита вашей таблицы или когда вы захотите сменить метатаблицу.

     

    Новая версия идет! Переписано с нуля, теперь больше безопасности и меньше нерабочести! Ну и сложности тоже поменьше. А то как то сложновато.


  12. Бывали ли у вас когда-нибудь такие ситуации, когда необходимо защитить какую-либо таблицу от записи? Например, вы пишите операционную систему в OpenComputers,

    и хотите хоть какую-то защиту от вирусов. Бедные таблицы всегда в очень большой опасности. С tprotect ваши таблицы будут в безопасности, так как другие программы вместо оригинала таблицы получат её зеркальную копию. А когда вы захотите снова в нее что-то записать, вы сможете это сделать (оригинал же у вас?). Вообщем вот ее код :

     

    local tprotect={}
    local raw_rawset=rawset -- Сохраняем rawset для дальнейшего пользования
    local raw_rawget=rawget -- Сохраняем rawget для дальнейшего пользования
    local getmetatable=getmetatable --
    local setmetatable=setmetatable --
    local type=type                 -- Дополнительная зашыта
    local error=error               --
    local assert=assert             --
    local protectid={}
    local nextid={}
    function rawget(t,k)
      if type(t)=="table" and raw_rawget(t,protectid) then
        error("СЕРЬЁЗНАЯ ПРОБЛЕМА БЕЗОПАСНОСТИ ДЕТЕКТЕД. УНИЧТОЖАЕМ ОПАСНОСТЬ...",2)
      end
      return raw_rawget(t,k)
    end
    local raw_next=next
    -- НИКТО НЕ ДОЛЖЕН УЗНАТЬ МАСТЕР-КЛЮЧ!!!
    function next(t,k)
      if type(t)=="table" and raw_rawget(t,protectid) then
        error("СЕРЬЁЗНАЯ ПРОБЛЕМА БЕЗОПАСНОСТИ ДЕТЕКТЕД. УНИЧТОЖАЕМ ОПАСНОСТЬ...",2)
      end
      local ok,k,v=xpcall(raw_next,debug.traceback,t,k)
      if not ok then
        error(k,0)
      end
      return k,v
    end
    local raw_ipairs=ipairs
    function ipairs(...)
      local f,t,z=raw_ipairs(...)
      return function(t,k)
        if type(t)=="table" and raw_rawget(t,protectid) then
          error("СЕРЬЁЗНАЯ ПРОБЛЕМА БЕЗОПАСНОСТИ ДЕТЕКТЕД. УНИЧТОЖАЕМ ОПАСНОСТЬ...",2)
        end
        return f(t,k)
      end,t,z
    end
    function rawset(t,k,v) -- Потому что в защитные копии таблиц можно было бы записывать. Хоть это бы и не отразилось бы на оригинале, но при попытке индекснуть поле защитной копии будет подложено подмененное поле в обход __index :(
      if k==protectid then
        error("СЕРЬЁЗНАЯ ПРОБЛЕМА БЕЗОПАСНОСТИ ДЕТЕКТЕД. УНИЧТОЖАЕМ ОПАСНОСТЬ...",2)
      end
      assert(type(t)=="table","bad argument #1 to rawset (table expected, got "..type(t)..")")
      assert(type(k)~="nil","bad argument #2 to rawset (table index is nil)")
      local mt=getmetatable(t)
      local no_set=raw_rawget(t,protectid) or (type(mt)=="table" and raw_rawget(mt,protectid))
      if no_set then
        error("таблица рид-онли! Аксес дэняйд!",2)
      end
      raw_rawset(t,k,v)
      return t
    end
    function tprotect.protect(t)
      local tcopy={[protectid]=true}
      local mto=getmetatable(t)
      local tcopy_mt=type(mto)=="table" and mto or {}
      local mt={[protectid]=true}
      function mt:__index(k)
        local x=t[k]
        if tcopy_mt.__index and not x then
          return tcopy_mt.__index(t,k)
        end
        return t[k]
      end
      function mt:__pairs(self)
        if tcopy_mt.__pairs then
          return tcopy_mt.__pairs(t)
        end
        local function iter(x,i)
          assert(x==self)
          return next(t,i)
        end
        return iter,self,nil
      end
      function mt:__ipairs(self)
        if tcopy_mt.__ipairs then
          return tcopy_mt.__ipairs(t)
        end
        local f,x,i=ipairs(self)
        local function iter(self,i)
          return f(t,i)
        end
        return iter,x,i
      end
      function mt:__newindex(k,v)
        if tcopy_mt.__newindex then -- Мы доверяем нашим клиентам!
          return tcopy_mt.__newindex(self,k,v)
        end
        error("СРЕДНЕНЬКАЯ ПРОБЛЕМА БЕЗОПАСНОСТИ ДЕТЕКТЕД. УНИЧТОЖАЕМ ОПАСНОСТЬ...",2)
      end
      mt.__metatable={"Хочешь проблем? Попытайся взломать tprotect!"}
      setmetatable(mt,{__index=function(self,i)
        local v=tcopy_mt
        if type(v)=="function" then
          return function(self,...)
            return v(t,...)
          end
        end
        return v
      end})
      setmetatable(tcopy,mt)
      return tcopy,tcopy_mt
    end
    local tprotect_t,tprotect_mt=tprotect.protect(tprotect) -- Защитим нашу библиотечку
    return tprotect_t

    А теперь документация, а то я пишу код непонятно:

    function tprotect.protect(table:t):table -- Возвращает "зеркало" таблицы t и её метатаблицу (у "зеркальной" таблицы она неизменяема). "Зеркальная" таблица защищена от записи и всегда является отражением t. Если вы хотите защитить таблицу t, то на публичное (доступное для других программ, от которых вам хотелось бы защитить t) место, где вы ставите обычно таблицу t, ставьте "зеркальную" таблицу

     

    • Нравится 6
×
×
  • Создать...