// Returns true if this opcode is an action opcode without actually // evaluating it. Used to do a quick scan forward to the next opcode group. boolIsAction()const{ return (OP_ACTION == opcode_id_); }
// Returns the opcode type. OpcodeID GetID()const{ return opcode_id_; }
// Returns the stored options such as kPolNegateEval and others. uint32_tGetOptions()const{ return options_; }
// Sets the stored options such as kPolNegateEval. voidSetOptions(uint32_t options){ options_ = options; }
// Returns the parameter of the function the opcode concerns. uint16_tGetParameter()const{ return parameter_; }
private: staticconstsize_t kArgumentCount = 4; // The number of supported argument.
structOpcodeArgument { UINT_PTR mem; }; // Better define placement new in the class instead of relying on the // global definition which seems to be fubared. void* operatornew(size_t, void* location){ return location; }
// opcode从top开始向下占用buffer PolicyOpcode* opcode = new (memory_top_) PolicyOpcode();
// Fill in the standard fields, that every opcode has. memory_top_ += sizeof(PolicyOpcode); opcode->opcode_id_ = opcode_id; // 标记 opcode type opcode->SetOptions(options); // 标记 opcode options // 传入的selected_param表示用于和该PolicyOpcode比较的参数在ParameterSet中是第几个,也就是索引 opcode->parameter_ = selected_param; return opcode; }
//chromium/sandbox/win/src/filesystem_policy.cc boolFileSystemPolicy::GenerateRules(constwchar_t* name, TargetPolicy::Semantics semantics, LowLevelPolicy* policy){ std::wstringmod_name(name); if (mod_name.empty()) { returnfalse; } //处理 mod_name。 if (!PreProcessName(&mod_name)) { // The path to be added might contain a reparse point. NOTREACHED(); returnfalse; }
// TODO(cpu) bug 32224: This prefix add is a hack because we don't have the // infrastructure to normalize names. In any case we need to escape the // question marks. if (_wcsnicmp(mod_name.c_str(), kNTDevicePrefix, kNTDevicePrefixLen)) { mod_name = FixNTPrefixForMatch(mod_name); name = mod_name.c_str(); } // 设定 ASK_broker EvalResult result = ASK_BROKER;
// List of supported calls for the filesystem. constunsigned kCallNtCreateFile = 0x1; constunsigned kCallNtOpenFile = 0x2; constunsigned kCallNtQueryAttributesFile = 0x4; constunsigned kCallNtQueryFullAttributesFile = 0x8; constunsigned kCallNtSetInfoRename = 0x10;
DWORD rule_to_add = kCallNtOpenFile | kCallNtCreateFile | kCallNtQueryAttributesFile | kCallNtQueryFullAttributesFile | kCallNtSetInfoRename; //创建 5 个PolicyRule,分别管制5种请求,action为ASK_BROKER PolicyRule create(result); PolicyRule open(result); PolicyRule query(result); PolicyRule query_full(result); PolicyRule rename(result); //根据不同的semantics,添加不同的 policy switch (semantics) { case TargetPolicy::FILES_ALLOW_DIR_ANY: { open.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND); create.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND); break; } case TargetPolicy::FILES_ALLOW_READONLY: { // We consider all flags that are not known to be readonly as potentially // used for write. DWORD allowed_flags = FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE | FILE_EXECUTE | GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL; DWORD restricted_flags = ~allowed_flags; open.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND); open.AddNumberMatch(IF, OpenFile::DISPOSITION, FILE_OPEN, EQUAL); create.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND); create.AddNumberMatch(IF, OpenFile::DISPOSITION, FILE_OPEN, EQUAL);
// Read only access don't work for rename. rule_to_add &= ~kCallNtSetInfoRename; break; } case TargetPolicy::FILES_ALLOW_QUERY: { // Here we don't want to add policy for the open or the create. rule_to_add &= ~(kCallNtOpenFile | kCallNtCreateFile | kCallNtSetInfoRename); break; } case TargetPolicy::FILES_ALLOW_ANY: { break; } default: { NOTREACHED(); returnfalse; } } // 根据当前rule_to_add的状态,把OpenFile::NAME这一参数进行设置 // PolicyRule add好以后,就通过policy->AddRule添加到LowLevelPolicy中 // 注意AddRule时会绑定service id和PolicyRule // filesystem子系统占用了5个service id,分别对应open, create, rename, query, queryFull if ((rule_to_add & kCallNtCreateFile) && (!create.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) || !policy->AddRule(IpcTag::NTCREATEFILE, &create))) { returnfalse; }
for (size_t i = 0; i < kMaxServiceCount; i++) { if (!policy_rules->entry[i]) continue; IpcTag service = static_cast<IpcTag>(i); results.SetKey(GetIpcTagAsString(service), //根据 service 去获取其policy_rules GetPolicyOpcodes(policy_rules, service)); } return results; }
GetPolicyRules内部又会调用GetIpcTagAsString来获取 Ipc 的 tag,如:NtCreateFile这些,然后紧接着对这些 tag 的 policy 进行解析,调用GetPolicyOpcodes
std::stringGetPolicyOpcode(const PolicyOpcode* opcode, bool continuation){ // See |policy_engine_opcodes.cc|. uint32_t args[4]; auto options = opcode->GetOptions(); //获取Options,如kPolNegateEval auto param = opcode->GetParameter(); //返回操作码所关系的函数的参数。 std::string condition;
if (options & kPolNegateEval) //检测 opcode 是否标志kPolNegateEval condition += "!(";
switch (opcode->GetID()) { case OP_ALWAYS_FALSE: condition += "false"; break; case OP_ALWAYS_TRUE: condition += "true"; break; case OP_NUMBER_MATCH: opcode->GetArgument(1, &args[1]); //返回存储的参数 if (args[1] == UINT32_TYPE) { //UINT32_TYPE:支持的 C++ 类型编码为数字 id opcode->GetArgument(0, &args[0]); condition += base::StringPrintf("p[%d] == %x", param, args[0]); } else { constvoid* match_ptr = nullptr; opcode->GetArgument(0, &match_ptr); condition += base::StringPrintf("p[%d] == %p", param, match_ptr); } break; case OP_NUMBER_MATCH_RANGE: opcode->GetArgument(0, &args[0]); opcode->GetArgument(1, &args[1]); condition += base::StringPrintf("%x <= p[%d] <= %x", args[0], param, args[1]); break; case OP_NUMBER_AND_MATCH: opcode->GetArgument(0, &args[0]); condition += base::StringPrintf("p[%d] & %x", param, args[0]); break; case OP_WSTRING_MATCH: { int pos; opcode->GetArgument(1, &args[1]); // Length. opcode->GetArgument(2, &pos); // Position. opcode->GetArgument(3, &args[3]); // Options. // These are not nul-terminated so we have to wrap them here. //检索字符串参数的实际地址 auto match_string = std::wstring(opcode->GetRelativeString(0), 0, static_cast<size_t>(args[1])); condition += GetStringMatchOperation(pos, args[3]); if (args[3] & CASE_INSENSITIVE) // if Options = 1 condition += "_i"; condition += base::StringPrintf("(p[%d], '%S')", param, match_string.c_str()); } break; case OP_ACTION: opcode->GetArgument(0, &args[0]); condition += GetOpcodeAction(static_cast<EvalResult>(args[0])); break; default: DCHECK(false) << "Unknown Opcode"; return"Unknown"; }
if (options & kPolNegateEval) condition += ")"; // If there is another rule add a joining token. if (continuation) { if (options & kPolUseOREval) condition += " || "; else condition += " && "; } return condition; }