Author: ahatanak Date: Mon Nov 5 23:05:14 2018 New Revision: 346211 URL: http://llvm.org/viewvc/llvm-project?rev=346211&view=rev Log: os_log: Allow specifying mask type in format string.
A mask type is a 1 to 8-byte string that follows the "mask." annotation in the format string. This enables obfuscating data in the event the provided privacy level isn't enabled. rdar://problem/36756282 Modified: cfe/trunk/include/clang/AST/FormatString.h cfe/trunk/include/clang/AST/OSLog.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/AST/OSLog.cpp cfe/trunk/lib/AST/PrintfFormatString.cpp cfe/trunk/lib/CodeGen/CGBuiltin.cpp cfe/trunk/lib/Sema/SemaChecking.cpp cfe/trunk/test/CodeGen/builtins.c cfe/trunk/test/SemaObjC/format-strings-oslog.m Modified: cfe/trunk/include/clang/AST/FormatString.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/FormatString.h?rev=346211&r1=346210&r2=346211&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/FormatString.h (original) +++ cfe/trunk/include/clang/AST/FormatString.h Mon Nov 5 23:05:14 2018 @@ -477,6 +477,7 @@ class PrintfSpecifier : public analyze_f OptionalFlag IsPublic; // '{public}' OptionalFlag IsSensitive; // '{sensitive}' OptionalAmount Precision; + StringRef MaskType; public: PrintfSpecifier() : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"), @@ -559,6 +560,9 @@ public: const OptionalFlag &isSensitive() const { return IsSensitive; } bool usesPositionalArg() const { return UsesPositionalArg; } + StringRef getMaskType() const { return MaskType; } + void setMaskType(StringRef S) { MaskType = S; } + /// Changes the specifier and length according to a QualType, retaining any /// flags or options. Returns true on success, or false when a conversion /// was not successful. @@ -691,6 +695,9 @@ public: return true; } + /// Handle mask types whose sizes are not between one and eight bytes. + virtual void handleInvalidMaskType(StringRef MaskType) {} + // Scanf-specific handlers. virtual bool HandleInvalidScanfConversionSpecifier( Modified: cfe/trunk/include/clang/AST/OSLog.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OSLog.h?rev=346211&r1=346210&r2=346211&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/OSLog.h (original) +++ cfe/trunk/include/clang/AST/OSLog.h Mon Nov 5 23:05:14 2018 @@ -52,7 +52,10 @@ public: // The item is corresponding to the '%m' format specifier, no value is // populated in the buffer and the runtime is loading the errno value. - ErrnoKind + ErrnoKind, + + // The item is a mask type. + MaskKind }; enum { @@ -72,10 +75,13 @@ private: CharUnits ConstValue; CharUnits Size; // size of the data, not including the header bytes unsigned Flags = 0; + StringRef MaskType; public: - OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags) - : TheKind(kind), TheExpr(expr), Size(size), Flags(flags) { + OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags, + StringRef maskType = StringRef()) + : TheKind(kind), TheExpr(expr), Size(size), Flags(flags), + MaskType(maskType) { assert(((Flags == 0) || (Flags == IsPrivate) || (Flags == IsPublic) || (Flags == IsSensitive)) && "unexpected privacy flag"); @@ -99,6 +105,8 @@ public: const Expr *getExpr() const { return TheExpr; } CharUnits getConstValue() const { return ConstValue; } CharUnits size() const { return Size; } + + StringRef getMaskType() const { return MaskType; } }; class OSLogBufferLayout { @@ -122,9 +130,10 @@ public: Items, [](const OSLogBufferItem &Item) { return Item.getIsPrivate(); }); } - bool hasNonScalar() const { + bool hasNonScalarOrMask() const { return llvm::any_of(Items, [](const OSLogBufferItem &Item) { - return Item.getKind() != OSLogBufferItem::ScalarKind; + return Item.getKind() != OSLogBufferItem::ScalarKind || + !Item.getMaskType().empty(); }); } @@ -132,7 +141,7 @@ public: unsigned char result = 0; if (hasPrivateItems()) result |= HasPrivateItems; - if (hasNonScalar()) + if (hasNonScalarOrMask()) result |= HasNonScalarItems; return result; } Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=346211&r1=346210&r2=346211&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Nov 5 23:05:14 2018 @@ -7902,6 +7902,8 @@ def warn_format_non_standard: Warning< def warn_format_non_standard_conversion_spec: Warning< "using length modifier '%0' with conversion specifier '%1' is not supported by ISO C">, InGroup<FormatNonStandard>, DefaultIgnore; +def err_invalid_mask_type_size : Error< + "mask type size must be between 1-byte and 8-bytes">; def warn_format_invalid_annotation : Warning< "using '%0' format specifier annotation outside of os_log()/os_trace()">, InGroup<Format>; Modified: cfe/trunk/lib/AST/OSLog.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/OSLog.cpp?rev=346211&r1=346210&r2=346211&view=diff ============================================================================== --- cfe/trunk/lib/AST/OSLog.cpp (original) +++ cfe/trunk/lib/AST/OSLog.cpp Mon Nov 5 23:05:14 2018 @@ -26,6 +26,7 @@ private: Optional<const Expr *> Precision; Optional<const Expr *> FieldWidth; unsigned char Flags = 0; + StringRef MaskType; }; SmallVector<ArgData, 4> ArgsData; ArrayRef<const Expr *> Args; @@ -127,12 +128,19 @@ public: else if (FS.isPublic()) ArgsData.back().Flags |= OSLogBufferItem::IsPublic; + ArgsData.back().MaskType = FS.getMaskType(); return true; } void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const { Layout.Items.clear(); for (auto &Data : ArgsData) { + if (!Data.MaskType.empty()) { + CharUnits Size = CharUnits::fromQuantity(8); + Layout.Items.emplace_back(OSLogBufferItem::MaskKind, nullptr, + Size, 0, Data.MaskType); + } + if (Data.FieldWidth) { CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType()); Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth, Modified: cfe/trunk/lib/AST/PrintfFormatString.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/PrintfFormatString.cpp?rev=346211&r1=346210&r2=346211&view=diff ============================================================================== --- cfe/trunk/lib/AST/PrintfFormatString.cpp (original) +++ cfe/trunk/lib/AST/PrintfFormatString.cpp Mon Nov 5 23:05:14 2018 @@ -127,7 +127,8 @@ static PrintfSpecifierResult ParsePrintf do { StringRef Str(I, E - I); - std::string Match = "^[[:space:]]*(private|public|sensitive)" + std::string Match = "^[[:space:]]*" + "(private|public|sensitive|mask\\.[^[:space:],}]*)" "[[:space:]]*(,|})"; llvm::Regex R(Match); SmallVector<StringRef, 2> Matches; @@ -139,7 +140,13 @@ static PrintfSpecifierResult ParsePrintf // Set the privacy flag if the privacy annotation in the // comma-delimited segment is at least as strict as the privacy // annotations in previous comma-delimited segments. - if (MatchedStr.equals("sensitive")) + if (MatchedStr.startswith("mask")) { + StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1); + unsigned Size = MaskType.size(); + if (Warn && (Size == 0 || Size > 8)) + H.handleInvalidMaskType(MaskType); + FS.setMaskType(MaskType); + } else if (MatchedStr.equals("sensitive")) PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive; else if (PrivacyFlags != clang::analyze_os_log::OSLogBufferItem::IsSensitive && Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=346211&r1=346210&r2=346211&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original) +++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Mon Nov 5 23:05:14 2018 @@ -1168,7 +1168,12 @@ RValue CodeGenFunction::emitBuiltinOSLog llvm::Value *ArgVal; - if (const Expr *TheExpr = Item.getExpr()) { + if (Item.getKind() == analyze_os_log::OSLogBufferItem::MaskKind) { + uint64_t Val = 0; + for (unsigned I = 0, E = Item.getMaskType().size(); I < E; ++I) + Val |= ((unsigned )Item.getMaskType()[I]) << I * 8; + ArgVal = llvm::Constant::getIntegerValue(Int64Ty, llvm::APInt(64, Val)); + } else if (const Expr *TheExpr = Item.getExpr()) { ArgVal = EmitScalarExpr(TheExpr, /*Ignore*/ false); // Check if this is a retainable type. Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=346211&r1=346210&r2=346211&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Nov 5 23:05:14 2018 @@ -7135,6 +7135,8 @@ public: const char *startSpecifier, unsigned specifierLen) override; + void handleInvalidMaskType(StringRef MaskType) override; + bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) override; @@ -7186,6 +7188,10 @@ bool CheckPrintfHandler::HandleInvalidPr CS.getStart(), CS.getLength()); } +void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) { + S.Diag(getLocationOfByte(MaskType.data()), diag::err_invalid_mask_type_size); +} + bool CheckPrintfHandler::HandleAmount( const analyze_format_string::OptionalAmount &Amt, unsigned k, const char *startSpecifier, Modified: cfe/trunk/test/CodeGen/builtins.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins.c?rev=346211&r1=346210&r2=346211&view=diff ============================================================================== --- cfe/trunk/test/CodeGen/builtins.c (original) +++ cfe/trunk/test/CodeGen/builtins.c Mon Nov 5 23:05:14 2018 @@ -454,6 +454,22 @@ void test_builtin_os_log(void *buf, int // CHECK: call void @__os_log_helper_1_3_1_8_37( __builtin_os_log_format(buf, "%{ private, sensitive, private, public}s", "abc"); + + // CHECK: store volatile i32 22, i32* %[[LEN]], align 4 + len = __builtin_os_log_format_buffer_size("%{mask.xyz}s", "abc"); + + // CHECK: call void @__os_log_helper_1_2_2_8_112_8_34(i8* {{.*}}, i64 8026488 + __builtin_os_log_format(buf, "%{mask.xyz, public}s", "abc"); + + // CHECK: call void @__os_log_helper_1_3_2_8_112_4_1(i8* {{.*}}, i64 8026488 + __builtin_os_log_format(buf, "%{ mask.xyz, private }d", 11); + + // Mask type is silently ignored. + // CHECK: call void @__os_log_helper_1_2_1_8_32( + __builtin_os_log_format(buf, "%{ mask. xyz }s", "abc"); + + // CHECK: call void @__os_log_helper_1_2_1_8_32( + __builtin_os_log_format(buf, "%{ mask.xy z }s", "abc"); } // CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_3_4_4_0_8_34_4_17_8_49 Modified: cfe/trunk/test/SemaObjC/format-strings-oslog.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/format-strings-oslog.m?rev=346211&r1=346210&r2=346211&view=diff ============================================================================== --- cfe/trunk/test/SemaObjC/format-strings-oslog.m (original) +++ cfe/trunk/test/SemaObjC/format-strings-oslog.m Mon Nov 5 23:05:14 2018 @@ -39,6 +39,10 @@ void test_os_log_format(const char *pc, struct { char data[0x100]; } toobig; __builtin_os_log_format(buf, "%s", toobig); // expected-error {{os_log() argument 2 is too big (256 bytes, max 255)}} + + __builtin_os_log_format(buf, "%{mask.xyz}s", "abc"); + __builtin_os_log_format(buf, "%{mask.}s", "abc"); // expected-error {{mask type size must be between 1-byte and 8-bytes}} + __builtin_os_log_format(buf, "%{mask.abcdefghi}s", "abc"); // expected-error {{mask type size must be between 1-byte and 8-bytes}} } // Test os_log_format primitive with ObjC string literal format argument. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits