r346211 - os_log: Allow specifying mask type in format string.

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 5 23:05:14 PST 2018


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.




More information about the cfe-commits mailing list