1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 #include <pthread.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/prctl.h>
24 
25 #include "private/ScopeGuard.h"
26 
27 extern "C" pid_t gettid();
28 
ProcSelfReadlinkBody()29 static void ProcSelfReadlinkBody() {
30   char buf[100];
31   char buf2[1024];
32   int fd = open("/dev/null", O_RDWR | O_CLOEXEC);
33   ASSERT_NE(-1, fd);
34   snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
35   const char* ERRORMSG = "Please apply the following two kernel patches:\n"
36     "* https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=73af963f9f3036dffed55c3a2898598186db1045\n"
37     "* https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=96d0df79f2644fc823f26c06491e182d87a90c2a\n";
38   ASSERT_NE(-1, readlink(buf, buf2, sizeof(buf2))) << ERRORMSG;
39   ASSERT_STREQ("/dev/null", buf2);
40   close(fd);
41 }
42 
ProcSelfReadlink(void *)43 static void* ProcSelfReadlink(void*) {
44   ProcSelfReadlinkBody();
45   return NULL;
46 }
47 
TEST(bug_26110743,ProcSelfReadlink)48 TEST(bug_26110743, ProcSelfReadlink) {
49   pthread_t t;
50   ASSERT_EQ(0, pthread_create(&t, NULL, ProcSelfReadlink, NULL));
51   void* result;
52   ASSERT_EQ(0, pthread_join(t, &result));
53   ASSERT_EQ(NULL, result);
54 }
55 
TEST(bug_26110743,ProcSelfReadlink_NotDumpable)56 TEST(bug_26110743, ProcSelfReadlink_NotDumpable) {
57   int dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
58   prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
59   auto guard = make_scope_guard([&]() {
60     // restore dumpable
61     prctl(PR_SET_DUMPABLE, dumpable, 0, 0, 0);
62   });
63 
64   pthread_t t;
65   ASSERT_EQ(0, pthread_create(&t, NULL, ProcSelfReadlink, NULL));
66   void* result;
67   ASSERT_EQ(0, pthread_join(t, &result));
68   ASSERT_EQ(NULL, result);
69 }
70 
ProcTaskFdReadlinkBody()71 static void ProcTaskFdReadlinkBody() {
72   char buf[200];
73   char buf2[1024];
74   int fd = open("/dev/null", O_RDWR | O_CLOEXEC);
75   ASSERT_NE(-1, fd);
76   pid_t mypid = getpid();
77   pid_t mytid = gettid();
78   ASSERT_NE(mypid, mytid);
79   snprintf(buf, sizeof(buf), "/proc/%d/task/%d/fd/%d", mypid, mytid, fd);
80   const char* ERRORMSG = "Please apply the following kernel patch:\n"
81     "* https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=54708d2858e79a2bdda10bf8a20c80eb96c20613\n";
82   ASSERT_NE(-1, readlink(buf, buf2, sizeof(buf2))) << ERRORMSG;
83   ASSERT_STREQ("/dev/null", buf2);
84   close(fd);
85 }
86 
ProcTaskFdReadlink(void *)87 static void* ProcTaskFdReadlink(void*) {
88   ProcTaskFdReadlinkBody();
89   return NULL;
90 }
91 
TEST(bug_26110743,ProcTaskFdReadlink)92 TEST(bug_26110743, ProcTaskFdReadlink) {
93   pthread_t t;
94   ASSERT_EQ(0, pthread_create(&t, NULL, ProcTaskFdReadlink, NULL));
95   void* result;
96   ASSERT_EQ(0, pthread_join(t, &result));
97   ASSERT_EQ(NULL, result);
98 }
99 
TEST(bug_26110743,ProcTaskFdReadlink_NotDumpable)100 TEST(bug_26110743, ProcTaskFdReadlink_NotDumpable) {
101   int dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
102   prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
103   auto guard = make_scope_guard([&]() {
104     // restore dumpable
105     prctl(PR_SET_DUMPABLE, dumpable, 0, 0, 0);
106   });
107 
108   pthread_t t;
109   ASSERT_EQ(0, pthread_create(&t, NULL, ProcTaskFdReadlink, NULL));
110   void* result;
111   ASSERT_EQ(0, pthread_join(t, &result));
112   ASSERT_EQ(NULL, result);
113 }
114