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
27extern "C" pid_t gettid();
28
29static 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
43static void* ProcSelfReadlink(void*) {
44  ProcSelfReadlinkBody();
45  return NULL;
46}
47
48TEST(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
56TEST(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
71static 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
87static void* ProcTaskFdReadlink(void*) {
88  ProcTaskFdReadlinkBody();
89  return NULL;
90}
91
92TEST(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
100TEST(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