Package: glibc / 2.41-10

hurd-i386/git-dup-refcnt.diff Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
commit e150ee870907e1c5ded4aad8d22a92a98f59d243
Author: Zhaoming Luo <zhmingluo@163.com>
Date:   Mon Mar 10 16:44:09 2025 +0800

    hurd: Check return value of mach_port_mod_refs() in the dup routine of fcntl()
    
    Message-ID: <20250310084409.24177-1-zhmingluo@163.com>

diff --git a/sysdeps/mach/hurd/dup3.c b/sysdeps/mach/hurd/dup3.c
index 22af45b491..49545ae63a 100644
--- a/sysdeps/mach/hurd/dup3.c
+++ b/sysdeps/mach/hurd/dup3.c
@@ -69,6 +69,7 @@ __dup3 (int fd, int fd2, int flags)
 	{
 	  /* Get a hold of the destination descriptor.  */
 	  struct hurd_fd *d2;
+	  error_t err;
 
 	  __mutex_lock (&_hurd_dtable_lock);
 
@@ -107,22 +108,51 @@ __dup3 (int fd, int fd2, int flags)
 	    }
 	  else
 	    {
-	      /* Give the ports each a user ref for the new descriptor.  */
-	      __mach_port_mod_refs (__mach_task_self (), port,
-				    MACH_PORT_RIGHT_SEND, 1);
-	      if (ctty != MACH_PORT_NULL)
-		__mach_port_mod_refs (__mach_task_self (), ctty,
-				      MACH_PORT_RIGHT_SEND, 1);
-
-	      /* Install the ports and flags in the new descriptor slot.  */
-	      __spin_lock (&d2->port.lock);
-	      if (flags & O_CLOEXEC)
-		d2->flags = d_flags | FD_CLOEXEC;
-	      else
-		/* dup clears FD_CLOEXEC.  */
-		d2->flags = d_flags & ~FD_CLOEXEC;
-	      _hurd_port_set (&d2->ctty, ctty);
-	      _hurd_port_locked_set (&d2->port, port); /* Unlocks D2.  */
+	      /* Give the io server port a user ref for the new descriptor.  */
+	      err = __mach_port_mod_refs (__mach_task_self (), port,
+					  MACH_PORT_RIGHT_SEND, 1);
+
+	      if (err == KERN_UREFS_OVERFLOW)
+		fd2 = __hurd_fail (EMFILE);
+	      else if (err)
+		fd2 = __hurd_fail (EINVAL);
+	      else if (ctty != MACH_PORT_NULL)
+		{
+		  /* We have confirmed the io server port has got a user ref
+		     count, now give ctty port a user ref for the new
+		     descriptor.  */
+		  err = __mach_port_mod_refs (__mach_task_self (), ctty,
+					      MACH_PORT_RIGHT_SEND, 1);
+
+		  if (err)
+		    {
+		      /* In this case the io server port has got a ref count
+		         but the ctty port failed to get one, so we need to
+			 clean the ref count we just assigned.  */
+		      __mach_port_mod_refs (__mach_task_self (), port,
+					    MACH_PORT_RIGHT_SEND, -1);
+
+		      if (err == KERN_UREFS_OVERFLOW)
+			fd2 = __hurd_fail (EMFILE);
+		      else
+			fd2 = __hurd_fail (EINVAL);
+		    }
+		}
+
+	      if (!err)
+	        {
+		  /* The ref counts of the ports are incremented
+		     successfully.  */
+		  /* Install the ports and flags in the new descriptor slot.  */
+		  __spin_lock (&d2->port.lock);
+		  if (flags & O_CLOEXEC)
+		    d2->flags = d_flags | FD_CLOEXEC;
+		  else
+		    /* dup clears FD_CLOEXEC.  */
+		    d2->flags = d_flags & ~FD_CLOEXEC;
+		  _hurd_port_set (&d2->ctty, ctty);
+		  _hurd_port_locked_set (&d2->port, port); /* Unlocks D2.  */
+		}
 	    }
 	}
 
diff --git a/sysdeps/mach/hurd/fcntl.c b/sysdeps/mach/hurd/fcntl.c
index a65c190cac..de576af1b7 100644
--- a/sysdeps/mach/hurd/fcntl.c
+++ b/sysdeps/mach/hurd/fcntl.c
@@ -83,18 +83,47 @@ __libc_fcntl (int fd, int cmd, ...)
 	  result = -1;
 	else
 	  {
-	    /* Give the ports each a user ref for the new descriptor.  */
-	    __mach_port_mod_refs (__mach_task_self (), port,
-				  MACH_PORT_RIGHT_SEND, 1);
-	    if (ctty != MACH_PORT_NULL)
-	      __mach_port_mod_refs (__mach_task_self (), ctty,
-				    MACH_PORT_RIGHT_SEND, 1);
-
-	    /* Install the ports and flags in the new descriptor.  */
-	    if (ctty != MACH_PORT_NULL)
-	      _hurd_port_set (&new->ctty, ctty);
-	    new->flags = flags;
-	    _hurd_port_locked_set (&new->port, port); /* Unlocks NEW.  */
+	    /* Give the io server port a user ref for the new descriptor.  */
+	    err = __mach_port_mod_refs (__mach_task_self (), port,
+					MACH_PORT_RIGHT_SEND, 1);
+
+	    if (err == KERN_UREFS_OVERFLOW)
+	      result = __hurd_fail (EMFILE);
+	    else if (err)
+	      result = __hurd_fail (EINVAL);
+	    else if (ctty != MACH_PORT_NULL)
+	      {
+		/* We have confirmed the io server port has got a user ref
+		   count, now give ctty port a user ref for the new
+		   descriptor.  */
+		err = __mach_port_mod_refs (__mach_task_self (), ctty,
+					    MACH_PORT_RIGHT_SEND, 1);
+
+		if (err)
+		  {
+		    /* In this case the io server port has got a ref count
+		    but the ctty port fails to get one, so we need to clean
+		    the ref count we just assigned.  */
+		    __mach_port_mod_refs (__mach_task_self (), port,
+					  MACH_PORT_RIGHT_SEND, -1);
+
+		    if (err == KERN_UREFS_OVERFLOW)
+		      result = __hurd_fail (EMFILE);
+		    else
+		      result = __hurd_fail (EINVAL);
+		  }
+	      }
+
+	    if (!err)
+	      {
+		/* The ref counts of the ports are incremented successfully.  */
+		/* Install the ports and flags in the new descriptor.  */
+		if (ctty != MACH_PORT_NULL)
+		  _hurd_port_set (&new->ctty, ctty);
+		new->flags = flags;
+		/* Unlocks NEW.  */
+		_hurd_port_locked_set (&new->port, port);
+	      }
 	  }
 
 	HURD_CRITICAL_END;